1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // EEToProfInterfaceImpl.cpp
9 // This module implements wrappers around calling the profiler's
10 // ICorProfilerCallaback* interfaces. When code in the EE needs to call the
11 // profiler, it goes through EEToProfInterfaceImpl to do so.
13 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
18 // There are strict rules for how to implement ICorProfilerCallback* wrappers. Please read
19 // https://github.com/dotnet/coreclr/blob/master/Documentation/botr/profilability.md
20 // to understand the rules and why they exist.
22 // As a reminder, here is a short summary of your responsibilities. Every PUBLIC
23 // ENTRYPOINT (from EE to profiler) must have:
25 // - An entrypoint macro at the top. Your choices are:
26 // CLR_TO_PROFILER_ENTRYPOINT (typical choice)
27 // This is used for calling ICorProfilerCallback* methods that either have no
28 // ThreadID parameters, or if they do have a ThreadID parameter, the parameter's
29 // value is always the *current* ThreadID (i.e., param == GetThread()). This will
30 // also force a mode switch to preemptive before calling the profiler.
31 // CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD
32 // Similar to above, except these are used for ICorProfilerCallback* methods that
33 // specify a ThreadID parameter whose value may not always be the *current*
34 // ThreadID. You must specify the ThreadID as the first parameter to these
35 // macros. The macro will then use your ThreadID rather than that of the current
36 // GetThread(), to assert that the callback is currently allowed for that
37 // ThreadID (i.e., that we have not yet issued a ThreadDestroyed() for that
40 // - A complete contract block with comments over every contract choice. Wherever
41 // possible, use the preferred contracts (if not possible, you must comment why):
43 // All callbacks are really NOTHROW, but that's enforced partially by
44 // the profiler, whose try/catch blocks aren't visible to the
45 // contract system. So you'll need to put a scoped
46 // PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout)
47 // around the call to the profiler
49 // MODE_PREEMPTIVE (MODE_COOPERATIVE if passing an ObjectID)
50 // If you use MODE_ANY, you must comment why you don't want an exact mode.
52 // ASSERT_NO_EE_LOCKS_HELD()
54 // Note that the preferred contracts in this file are DIFFERENT than the preferred
55 // contracts for proftoeeinterfaceimpl.cpp.
57 // Private helper functions in this file do not have the same preferred contracts as
58 // public entrypoints, and they should be contracted following the same guidelines
59 // as per the rest of the EE.
61 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
62 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
65 // ======================================================================================
69 #ifdef PROFILING_SUPPORTED
72 #include "eetoprofinterfaceimpl.h"
73 #include "eetoprofinterfaceimpl.inl"
75 #include "proftoeeinterfaceimpl.h"
76 #include "proftoeeinterfaceimpl.inl"
77 #include "profilinghelper.inl"
78 #include "profdetach.h"
79 #include "simplerwlock.hpp"
82 //---------------------------------------------------------------------------------------
85 // Bitmask of flags that may be passed to the CLR_TO_PROFILER_ENTRYPOINT* macros
86 // to constrain when the callback may be issued
87 enum ClrToProfEntrypointFlags
90 kEE2PNone = 0x00000000,
92 // Callback is allowable even for detaching profilers
93 kEE2PAllowableWhileDetaching = 0x00000001,
95 // Callback is allowable even for initializing profilers
96 kEE2PAllowableWhileInitializing = 0x00000002,
98 // Callback is made while in a GC_NOTRIGGER contract. Whereas contracts are
99 // debug-only, this flag is used in retail builds as well.
100 kEE2PNoTrigger = 0x00000004,
103 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
104 #define ASSERT_EVAC_COUNTER_NONZERO() \
105 _ASSERTE((GetThreadNULLOk() == NULL) || \
106 (GetThreadNULLOk()->GetProfilerEvacuationCounter() != 0U))
107 #else // FEATURE_PROFAPI_ATTACH_DETACH
108 #define ASSERT_EVAC_COUNTER_NONZERO()
109 #endif // FEATURE_PROFAPI_ATTACH_DETACH
111 #define CHECK_PROFILER_STATUS(ee2pFlags) \
112 /* If one of these asserts fires, perhaps you forgot to use */ \
113 /* BEGIN/END_PIN_PROFILER */ \
114 ASSERT_EVAC_COUNTER_NONZERO(); \
115 _ASSERTE(g_profControlBlock.pProfInterface.Load() != NULL); \
116 _ASSERTE(g_profControlBlock.pProfInterface == this); \
117 /* Early abort if... */ \
119 /* Profiler isn't active, */ \
120 !CORProfilerPresent() && \
122 /* and it's not the case that both a) this callback is allowed */ \
123 /* on a detaching profiler, and b) the profiler is detaching */ \
125 (((ee2pFlags) & kEE2PAllowableWhileDetaching) != 0) && \
126 (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching) \
129 /* and it's not the case that both a) this callback is allowed */ \
130 /* on an initializing profiler, and b) the profiler is initializing */ \
132 (((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) && \
134 (g_profControlBlock.curProfStatus.Get() \
135 == kProfStatusInitializingForStartupLoad) || \
136 (g_profControlBlock.curProfStatus.Get() \
137 == kProfStatusInitializingForAttachLoad) \
145 // Least common denominator for the callback wrappers. Logs, removes stack
146 // guard (REMOVE_STACK_GUARD_FOR_PROFILER_CALL), records in EE Thread object that
147 // we're in a callback, and asserts that we're allowed to issue callbacks for the
148 // specified ThreadID (i.e., no ThreadDestroyed callback has been issued for the
151 #define CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(ee2pFlags, threadId, logParams) \
152 INCONTRACT(AssertTriggersContract(!((ee2pFlags) & kEE2PNoTrigger))); \
153 CHECK_PROFILER_STATUS(ee2pFlags); \
155 _ASSERTE(m_pCallback2 != NULL); \
156 REMOVE_STACK_GUARD_FOR_PROFILER_CALL; \
157 /* Normally, set COR_PRF_CALLBACKSTATE_INCALLBACK | */ \
158 /* COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE in the callback state, but omit */ \
159 /* COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE if we're in a GC_NOTRIGGERS callback */ \
160 SetCallbackStateFlagsHolder __csf( \
161 (((ee2pFlags) & kEE2PNoTrigger) != 0) ? \
162 COR_PRF_CALLBACKSTATE_INCALLBACK : \
163 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE \
165 _ASSERTE(ProfilerCallbacksAllowedForThread((Thread *) (threadId)))
167 #define CLR_TO_PROFILER_ENTRYPOINT_EX(ee2pFlags, logParams) \
168 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(ee2pFlags, GetThreadNULLOk(), logParams)
170 // Typical entrypoint macro you'll use. Checks that we're allowed to issue
171 // callbacks for the current thread (i.e., no ThreadDestroyed callback has been
172 // issued for the current thread).
173 #define CLR_TO_PROFILER_ENTRYPOINT(logParams) \
174 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PNone, logParams)
175 #define CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId, logParams) \
176 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(kEE2PNone, threadId, logParams)
179 //---------------------------------------------------------------------------------------
181 // Wrapper around Thread::ProfilerCallbacksAllowed
184 // pThread - Thread on which we need to determine whether callbacks are allowed
187 // TRUE if the profiler portion has marked this thread as allowable, else FALSE.
190 inline BOOL ProfilerCallbacksAllowedForThread(Thread * pThread)
193 return ((pThread == NULL) || (pThread->ProfilerCallbacksAllowed()));
197 //---------------------------------------------------------------------------------------
199 // Wrapper around Thread::SetProfilerCallbacksAllowed
202 // pThread - Thread on which we're setting whether callbacks shall be allowed
203 // fValue - The value to store.
206 inline void SetProfilerCallbacksAllowedForThread(Thread * pThread, BOOL fValue)
209 _ASSERTE(pThread != NULL);
210 pThread->SetProfilerCallbacksAllowed(fValue);
214 //---------------------------------------------------------------------------------------
216 // Low-level function to find and CoCreateInstance the profiler's DLL. Called when
217 // initializing via EEToProfInterfaceImpl::Init()
220 // * pClsid - [in] Profiler's CLSID
221 // * wszClsid - [in] String form of CLSID or progid of profiler to load.
222 // * wszProfileDLL - [in] Path to profiler DLL
223 // * ppCallback - [out] Pointer to profiler's ICorProfilerCallback2 interface
224 // * phmodProfilerDLL - [out] HMODULE of profiler's DLL.
227 // HRESULT indicating success or failure.
230 // * This function (or one of its callees) will log an error to the event log if
231 // there is a failure
233 static HRESULT CoCreateProfiler(
234 const CLSID * pClsid,
235 __in_z LPCWSTR wszClsid,
236 __in_z LPCWSTR wszProfileDLL,
237 ICorProfilerCallback2 ** ppCallback,
238 HMODULE * phmodProfilerDLL)
246 // This causes events to be logged, which loads resource strings,
247 // which takes locks.
253 _ASSERTE(pClsid != NULL);
254 _ASSERTE(wszClsid != NULL);
255 _ASSERTE(ppCallback != NULL);
256 _ASSERTE(phmodProfilerDLL != NULL);
258 LOG((LF_CORPROF, LL_INFO10, "**PROF: Entered CoCreateProfiler.\n"));
261 *phmodProfilerDLL = NULL;
263 // This is the ICorProfilerCallback2 ptr we get back from the profiler's class
264 // factory's CreateInstance()
265 ReleaseHolder<ICorProfilerCallback2> pCallback2FromCreateInstance;
267 // This is the ICorProfilerCallback2 ptr we get back from the profiler's QI (see its
268 // first use below for an explanation on why this is necessary).
269 ReleaseHolder<ICorProfilerCallback2> pCallback2FromQI;
271 // Create an instance of the profiler
272 hr = FakeCoCreateInstanceEx(*pClsid,
274 IID_ICorProfilerCallback2,
275 (LPVOID *) &pCallback2FromCreateInstance,
278 // (pCallback2FromCreateInstance == NULL) should be considered an error!
279 if ((pCallback2FromCreateInstance == NULL) && SUCCEEDED(hr))
284 if (hr == E_NOINTERFACE)
286 // Helpful message for a potentially common problem
287 ProfilingAPIUtility::LogNoInterfaceError(IID_ICorProfilerCallback2, wszClsid);
289 else if (hr == CORPROF_E_PROFILER_CANCEL_ACTIVATION)
291 // Profiler didn't encounter a bad error, but is voluntarily choosing not to
292 // profile this runtime. Profilers that need to set system environment
293 // variables to be able to profile services may use this HRESULT to avoid
294 // profiling all the other managed apps on the box.
295 ProfilingAPIUtility::LogProfInfo(IDS_PROF_CANCEL_ACTIVATION, wszClsid);
299 // Catch-all error for other CoCreateInstance failures
300 ProfilingAPIUtility::LogProfError(IDS_E_PROF_CCI_FAILED, wszClsid, hr);
303 // Now that hr is normalized (set to error if pCallback2FromCreateInstance == NULL),
304 // LOG and abort if there was a problem.
310 "**PROF: Unable to CoCreateInstance profiler class %S. hr=0x%x.\n",
316 // Redundantly QI for ICorProfilerCallback2. This keeps CLR behavior consistent
317 // with Whidbey, and works around the following bug in some profilers' class factory
319 // * CreateInstance() ignores the IID it's given
320 // * CreateInstance() returns a pointer to the object it created, even though
321 // that object might not support the IID passed to CreateInstance().
322 // Whidbey CLR worked around this problem by redundantly QI'ing for the same IID
323 // again after CreateInstance() returned. In this redudant QI, the profiler code would
324 // finally realize it didn't support that IID, and return an error there. Without
325 // the redundant QI, the CLR would accept what it got from CreateInstance(), and
326 // start calling into it using the unsupported interface's vtable, which would
329 // There were many MSDN samples (for example
330 // http://msdn.microsoft.com/msdnmag/issues/03/01/NETProfilerAPI/) which
331 // unfortunately had this CreateInstance() bug, so many profilers might have been
332 // generated based on this code. Since it's easy & cheap to work around the
333 // problem, we do so here with the redundant QI.
334 hr = pCallback2FromCreateInstance->QueryInterface(
335 IID_ICorProfilerCallback2,
336 (LPVOID *) &pCallback2FromQI);
338 // (pCallback2FromQI == NULL) should be considered an error!
339 if ((pCallback2FromQI == NULL) && SUCCEEDED(hr))
344 // Any error at this stage implies IID_ICorProfilerCallback2 is not supported
347 // Helpful message for a potentially common problem
348 ProfilingAPIUtility::LogNoInterfaceError(IID_ICorProfilerCallback2, wszClsid);
352 // Ok, safe to transfer ownership to caller's [out] param
353 *ppCallback = pCallback2FromQI.Extract();
354 pCallback2FromQI = NULL;
360 //---------------------------------------------------------------------------------------
362 // Implementation of CHashTableImpl functions. This class a simple implementation of
363 // CHashTable to provide a very simple implementation of the Cmp pure virtual function
366 EEToProfInterfaceImpl::CHashTableImpl::CHashTableImpl(ULONG iBuckets)
367 : CHashTable(iBuckets)
372 EEToProfInterfaceImpl::CHashTableImpl::~CHashTableImpl()
377 //---------------------------------------------------------------------------------------
379 // Comparison function for hash table of ClassIDs
382 // pc1 - hash key to compare
383 // pc2 - hash value to compare
386 // TRUE if the key & value refer to the same ClassID; otherwise FALSE
389 BOOL EEToProfInterfaceImpl::CHashTableImpl::Cmp(SIZE_T k1, const HASHENTRY * pc2)
391 LIMITED_METHOD_CONTRACT;
393 ClassID key = (ClassID) k1;
394 ClassID val = ((CLASSHASHENTRY *)pc2)->m_clsId;
400 //---------------------------------------------------------------------------------------
401 // Private maintenance functions for initialization, cleanup, etc.
403 EEToProfInterfaceImpl::AllocByClassData *EEToProfInterfaceImpl::m_pSavedAllocDataBlock = NULL;
405 //---------------------------------------------------------------------------------------
407 // EEToProfInterfaceImpl ctor just sets initial values
410 EEToProfInterfaceImpl::EEToProfInterfaceImpl() :
417 m_hmodProfilerDLL(NULL),
418 m_fLoadedViaAttach(FALSE),
420 m_pProfilersFuncIDMapper(NULL),
421 m_pProfilersFuncIDMapper2(NULL),
422 m_pProfilersFuncIDMapper2ClientData(NULL),
425 m_pGCRefDataFreeList(NULL),
426 m_csGCRefDataFreeList(NULL),
433 m_fIsClientIDToFunctionIDMappingEnabled(TRUE),
437 m_pEnter3WithInfo(NULL),
438 m_pLeave3WithInfo(NULL),
439 m_pTailcall3WithInfo(NULL),
440 m_fUnrevertiblyModifiedIL(FALSE),
441 m_pFunctionIDHashTable(NULL),
442 m_pFunctionIDHashTableRWLock(NULL),
443 m_dwConcurrentGCWaitTimeoutInMs(INFINITE),
444 m_bHasTimedOutWaitingForConcurrentGC(FALSE)
446 // Also NULL out this static. (Note: consider making this a member variable.)
447 m_pSavedAllocDataBlock = NULL;
448 LIMITED_METHOD_CONTRACT;
452 //---------------------------------------------------------------------------------------
454 // Post-constructor initialization of EEToProfInterfaceImpl. Sets everything up,
455 // including creating the profiler.
458 // * pProfToEE - A newly-created ProfToEEInterfaceImpl instance that will be passed
459 // to the profiler as the ICorProfilerInfo3 interface implementation.
460 // * pClsid - Profiler's CLSID
461 // * wszClsid - String form of CLSID or progid of profiler to load
462 // * wszProfileDLL - Path to profiler DLL
463 // * fLoadedViaAttach - TRUE iff the profiler is being attach-loaded (else
464 // profiler is being startup-loaded)
467 // HRESULT indicating success or failure.
470 // This function (or one of its callees) will log an error to the event log if there
475 HRESULT EEToProfInterfaceImpl::Init(
476 ProfToEEInterfaceImpl * pProfToEE,
477 const CLSID * pClsid,
478 __in_z LPCWSTR wszClsid,
479 __in_z LPCWSTR wszProfileDLL,
480 BOOL fLoadedViaAttach,
481 DWORD dwConcurrentGCWaitTimeoutInMs)
489 // This causes events to be logged, which loads resource strings,
490 // which takes locks.
497 HRESULT hr = E_UNEXPECTED;
499 _ASSERTE(pProfToEE != NULL);
501 m_fLoadedViaAttach = fLoadedViaAttach;
502 m_dwConcurrentGCWaitTimeoutInMs = dwConcurrentGCWaitTimeoutInMs;
504 // The rule sez your Crst should switch to preemptive when it's taken. We intentionally
505 // break this rule with CRST_UNSAFE_ANYMODE, because this Crst is taken DURING A GC
506 // (see AllocateMovedReferencesData(), called by MovedReference(), called by the GC),
507 // and we don't want to be switching modes in the middle of a GC! Indeed, on server there
508 // may not even be a mode in the first place.
509 CRITSEC_AllocationHolder csGCRefDataFreeList(ClrCreateCriticalSection(CrstProfilerGCRefDataFreeList, CRST_UNSAFE_ANYMODE));
510 if (csGCRefDataFreeList == NULL)
514 "**PROF: Failed to create Crst during initialization.\n"));
516 // A specialized event log entry for this failure would be confusing and
517 // unhelpful. So just log a generic internal failure event
518 ProfilingAPIUtility::LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_FAIL);
522 // CEEInfo::GetProfilingHandle will be PREEMPTIVE mode when trying to update
523 // m_pFunctionIDHashTable while ProfileEnter, ProfileLeave and ProfileTailcall
524 // and LookupClientIDFromCache all will be in COOPERATIVE mode when trying
525 // to read m_pFunctionIDHashTable, so pFunctionIDHashTableRWLock must be created
526 // with COOPERATIVE_OR_PREEMPTIVE. It is safe to so do because FunctionIDHashTable,
527 // synchronized by m_pFunctionIDHashTableRWLock runs only native code and uses
529 NewHolder<SimpleRWLock> pFunctionIDHashTableRWLock(new (nothrow) SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT));
531 NewHolder<FunctionIDHashTable> pFunctionIDHashTable(new (nothrow) FunctionIDHashTable());
533 if ((pFunctionIDHashTable == NULL) || (pFunctionIDHashTableRWLock == NULL))
537 "**PROF: Failed to create FunctionIDHashTable or FunctionIDHashTableRWLock during initialization.\n"));
539 // A specialized event log entry for this failure would be confusing and
540 // unhelpful. So just log a generic internal failure event
541 ProfilingAPIUtility::LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_OUTOFMEMORY);
543 return E_OUTOFMEMORY;
546 // This wraps the following profiler calls in a try / catch:
547 // * ClassFactory::CreateInstance
548 // * AddRef/Release/QueryInterface
549 // Although most profiler calls are not protected, these creation calls are
550 // protected here since it's cheap to do so (this is only done once per load of a
551 // profiler), and it would be nice to avoid tearing down the entire process when
552 // attaching a profiler that may pass back bogus vtables.
555 // CoCreate the profiler (but don't call its Initialize() method yet)
556 hr = CreateProfiler(pClsid, wszClsid, wszProfileDLL);
561 ProfilingAPIUtility::LogProfError(IDS_E_PROF_UNHANDLED_EXCEPTION_ON_LOAD, wszClsid);
563 // Intentionally swallowing all exceptions, as we don't want a poorly-written
564 // profiler that throws or AVs on attach to cause the entire process to go away.
565 EX_END_CATCH(SwallowAllExceptions);
570 // CreateProfiler (or catch clause above) has already logged an event to the
571 // event log on failure
575 m_pProfToEE = pProfToEE;
577 m_csGCRefDataFreeList = csGCRefDataFreeList.Extract();
578 csGCRefDataFreeList = NULL;
580 m_pFunctionIDHashTable = pFunctionIDHashTable.Extract();
581 pFunctionIDHashTable = NULL;
583 m_pFunctionIDHashTableRWLock = pFunctionIDHashTableRWLock.Extract();
584 pFunctionIDHashTableRWLock = NULL;
590 //---------------------------------------------------------------------------------------
592 // This is used by Init() to load the user-specified profiler (but not to call
593 // its Initialize() method).
596 // pClsid - Profiler's CLSID
597 // wszClsid - String form of CLSID or progid of profiler to load
598 // wszProfileDLL - Path to profiler DLL
601 // HRESULT indicating success / failure. If this is successful, m_pCallback2 will be
602 // set to the profiler's ICorProfilerCallback2 interface on return. m_pCallback3,4
603 // will be set to the profiler's ICorProfilerCallback3 interface on return if
604 // ICorProfilerCallback3,4 is supported.
607 // Although the profiler has not yet been instantiated, it is assumed that the internal
608 // profiling API structures have already been created
611 // This function (or one of its callees) will log an error to the event log
612 // if there is a failure
614 HRESULT EEToProfInterfaceImpl::CreateProfiler(
615 const CLSID * pClsid,
616 __in_z LPCWSTR wszClsid,
617 __in_z LPCWSTR wszProfileDLL)
625 // This causes events to be logged, which loads resource strings,
626 // which takes locks.
634 // Always called before Thread created.
635 _ASSERTE(GetThreadNULLOk() == NULL);
637 // We'll be calling into the profiler to create its ICorProfilerCallback*
639 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
641 // Try and CoCreate the registered profiler
642 ReleaseHolder<ICorProfilerCallback2> pCallback2;
643 HModuleHolder hmodProfilerDLL;
644 HRESULT hr = CoCreateProfiler(
652 // CoCreateProfiler logs events to the event log on failures
656 // CoCreateProfiler ensures that if it succeeds, we get some valid pointers
657 _ASSERTE(pCallback2 != NULL);
658 _ASSERTE(hmodProfilerDLL != NULL);
660 // Save profiler pointers into this. The reference ownership now
661 // belongs to this class, so NULL out locals without allowing them to release
662 m_pCallback2 = pCallback2.Extract();
664 m_hmodProfilerDLL = hmodProfilerDLL.Extract();
665 hmodProfilerDLL = NULL;
667 // The profiler may optionally support ICorProfilerCallback3,4,5,6,7. Let's check.
669 ReleaseHolder<ICorProfilerCallback7> pCallback7;
670 hr = m_pCallback2->QueryInterface(
671 IID_ICorProfilerCallback7,
672 (LPVOID *)&pCallback7);
673 if (SUCCEEDED(hr) && (pCallback7 != NULL))
675 // Nifty. Transfer ownership to this class
676 _ASSERTE(m_pCallback7 == NULL);
677 m_pCallback7 = pCallback7.Extract();
680 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6
681 // due to inheritance relationship of the interfaces
682 _ASSERTE(m_pCallback6 == NULL);
683 m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
684 m_pCallback6->AddRef();
686 _ASSERTE(m_pCallback5 == NULL);
687 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
688 m_pCallback5->AddRef();
690 _ASSERTE(m_pCallback4 == NULL);
691 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
692 m_pCallback4->AddRef();
694 _ASSERTE(m_pCallback3 == NULL);
695 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
696 m_pCallback3->AddRef();
699 if (m_pCallback6 == NULL)
701 ReleaseHolder<ICorProfilerCallback6> pCallback6;
702 hr = m_pCallback2->QueryInterface(
703 IID_ICorProfilerCallback6,
704 (LPVOID *)&pCallback6);
705 if (SUCCEEDED(hr) && (pCallback6 != NULL))
707 // Nifty. Transfer ownership to this class
708 _ASSERTE(m_pCallback6 == NULL);
709 m_pCallback6 = pCallback6.Extract();
712 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5
713 // due to inheritance relationship of the interfaces
715 _ASSERTE(m_pCallback5 == NULL);
716 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
717 m_pCallback5->AddRef();
719 _ASSERTE(m_pCallback4 == NULL);
720 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
721 m_pCallback4->AddRef();
723 _ASSERTE(m_pCallback3 == NULL);
724 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
725 m_pCallback3->AddRef();
729 if (m_pCallback5 == NULL)
731 ReleaseHolder<ICorProfilerCallback5> pCallback5;
732 hr = m_pCallback2->QueryInterface(
733 IID_ICorProfilerCallback5,
734 (LPVOID *) &pCallback5);
735 if (SUCCEEDED(hr) && (pCallback5 != NULL))
737 // Nifty. Transfer ownership to this class
738 _ASSERTE(m_pCallback5 == NULL);
739 m_pCallback5 = pCallback5.Extract();
742 // And while we're at it, we must now also have an ICorProfilerCallback3, and
743 // ICorProfilerCallback4 due to inheritance relationship of the interfaces
744 _ASSERTE(m_pCallback4 == NULL);
745 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
746 m_pCallback4->AddRef();
748 _ASSERTE(m_pCallback3 == NULL);
749 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
750 m_pCallback3->AddRef();
754 if (m_pCallback4 == NULL)
756 ReleaseHolder<ICorProfilerCallback4> pCallback4;
757 hr = m_pCallback2->QueryInterface(
758 IID_ICorProfilerCallback4,
759 (LPVOID *) &pCallback4);
760 if (SUCCEEDED(hr) && (pCallback4 != NULL))
762 // Nifty. Transfer ownership to this class
763 _ASSERTE(m_pCallback4 == NULL);
764 m_pCallback4 = pCallback4.Extract();
767 // And while we're at it, we must now also have an ICorProfilerCallback3, and
768 // due to inheritance relationship of the interfaces
769 _ASSERTE(m_pCallback3 == NULL);
770 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
771 m_pCallback3->AddRef();
775 if (m_pCallback3 == NULL)
777 ReleaseHolder<ICorProfilerCallback3> pCallback3;
778 hr = m_pCallback2->QueryInterface(
779 IID_ICorProfilerCallback3,
780 (LPVOID *) &pCallback3);
781 if (SUCCEEDED(hr) && (pCallback3 != NULL))
783 // Nifty. Transfer ownership to this class
784 _ASSERTE(m_pCallback3 == NULL);
785 m_pCallback3 = pCallback3.Extract();
796 //---------------------------------------------------------------------------------------
798 // Performs cleanup for EEToProfInterfaceImpl, including releasing the profiler's
799 // callback interface. Called on termination of a profiler connection.
802 EEToProfInterfaceImpl::~EEToProfInterfaceImpl()
810 // When we release the profiler's callback interface
811 // below, it may well perform cleanup that takes locks.
812 // Example: profiler may release a metadata interface, which
813 // causes it to take a reader lock
818 // Make sure there's no pointer about to dangle once we disappear.
819 // FUTURE: For reattach-with-neutered-profilers feature crew, change this assert to
820 // scan through list of detaching profilers to make sure none of them give a
821 // GetEEToProfPtr() equal to this
822 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
823 _ASSERTE(ProfilingAPIDetach::GetEEToProfPtr() == NULL);
824 #endif // FEATURE_PROFAPI_ATTACH_DETACH
826 // Release user-specified profiler DLL
827 // NOTE: If we're tearing down the process, then do nothing related
828 // to cleaning up the profiler DLL, as the DLL may no longer
830 if (!IsAtProcessExit())
832 if (m_pCallback2 != NULL)
834 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
835 m_pCallback2->Release();
839 BOOL fIsV4Profiler = (m_pCallback3 != NULL);
843 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
844 m_pCallback3->Release();
848 if (m_pCallback4 != NULL)
850 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
851 m_pCallback4->Release();
855 if (m_pCallback5 != NULL)
857 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
858 m_pCallback5->Release();
862 if (m_pCallback6 != NULL)
864 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
865 m_pCallback6->Release();
869 if (m_pCallback7 != NULL)
871 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
872 m_pCallback7->Release();
876 // Only unload the V4 profiler if this is not part of shutdown. This protects
877 // Whidbey profilers that aren't used to being FreeLibrary'd.
878 if (fIsV4Profiler && !g_fEEShutDown)
880 if (m_hmodProfilerDLL != NULL)
882 FreeLibrary(m_hmodProfilerDLL);
883 m_hmodProfilerDLL = NULL;
886 // Now that the profiler is destroyed, it is no longer referencing our
887 // ProfToEEInterfaceImpl, so it's safe to destroy that, too.
888 if (m_pProfToEE != NULL)
896 // Delete the structs associated with GC moved references
897 while (m_pGCRefDataFreeList)
899 GCReferencesData * pDel = m_pGCRefDataFreeList;
900 m_pGCRefDataFreeList = m_pGCRefDataFreeList->pNext;
904 if (m_pSavedAllocDataBlock)
907 _ASSERTE((UINT_PTR)m_pSavedAllocDataBlock != 0xFFFFFFFFFFFFFFFF);
909 _ASSERTE((UINT_PTR)m_pSavedAllocDataBlock != 0xFFFFFFFF);
912 _ASSERTE(m_pSavedAllocDataBlock->pHashTable != NULL);
913 // Get rid of the hash table
914 if (m_pSavedAllocDataBlock->pHashTable)
915 delete m_pSavedAllocDataBlock->pHashTable;
917 // Get rid of the two arrays used to hold class<->numinstance info
918 if (m_pSavedAllocDataBlock->cLength != 0)
920 _ASSERTE(m_pSavedAllocDataBlock->arrClsId != NULL);
921 _ASSERTE(m_pSavedAllocDataBlock->arrcObjects != NULL);
923 delete [] m_pSavedAllocDataBlock->arrClsId;
924 delete [] m_pSavedAllocDataBlock->arrcObjects;
927 // Get rid of the hash array used by the hash table
928 if (m_pSavedAllocDataBlock->arrHash)
930 delete [] m_pSavedAllocDataBlock->arrHash;
933 m_pSavedAllocDataBlock = NULL;
938 if (m_csGCRefDataFreeList != NULL)
940 ClrDeleteCriticalSection(m_csGCRefDataFreeList);
941 m_csGCRefDataFreeList = NULL;
944 if (m_pFunctionIDHashTable != NULL)
946 delete m_pFunctionIDHashTable;
947 m_pFunctionIDHashTable = NULL;
950 if (m_pFunctionIDHashTableRWLock != NULL)
952 delete m_pFunctionIDHashTableRWLock;
953 m_pFunctionIDHashTableRWLock = NULL;
959 //---------------------------------------------------------------------------------------
961 // Initialize the GUID used for the cookie in remoting callbacks. If already
962 // initialized, this just does nothing and returns S_OK.
965 // HRESULT indicating success or failure. If the GUID was already initialized,
970 HRESULT EEToProfInterfaceImpl::InitGUID()
977 ASSERT_NO_EE_LOCKS_HELD();
981 if (IsEqualGUID(m_GUID, k_guidZero))
983 return CoCreateGuid(&m_GUID);
989 //---------------------------------------------------------------------------------------
991 // Returns a GUID suitable for use as a remoting callback cookie for this thread.
992 // The GUID is based on the template GUID (m_GUID), the current thread, and
996 // pGUID - [out] The GUID requested
999 void EEToProfInterfaceImpl::GetGUID(GUID * pGUID)
1005 ASSERT_NO_EE_LOCKS_HELD();
1009 // the member GUID and the argument should both be valid
1010 _ASSERTE(!(IsEqualGUID(m_GUID, k_guidZero)));
1013 // Copy the contents of the template GUID
1014 memcpy(pGUID, &m_GUID, sizeof(GUID));
1016 // Adjust the last two bytes
1017 pGUID->Data4[6] = (BYTE) GetCurrentThreadId();
1018 pGUID->Data4[7] = (BYTE) InterlockedIncrement((LPLONG)&m_lGUIDCount);
1021 //---------------------------------------------------------------------------------------
1023 // Wrapper around calling profiler's FunctionIDMapper hook. Called by JIT.
1026 // funcId - FunctionID for profiler to map
1027 // pbHookFunction - [out] Specifies whether the profiler wants to hook (enter/leave)
1031 // The profiler-specified value that we should use to identify this function
1032 // in future hooks (enter/leave).
1033 // If the remapped ID returned by the profiler is NULL, we will replace it with
1034 // funcId. Thus, this function will never return NULL.
1037 UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction)
1039 // This isn't a public callback via ICorProfilerCallback*, but it's close (a
1040 // public callback via a function pointer). So we'll aim to have the preferred
1056 // ListLockEntry typically held during this callback (thanks to
1057 // MethodTable::DoRunClassInitThrowing).
1063 // only called when CORProfilerFunctionIDMapperEnabled() is true,
1064 // which means either m_pProfilersFuncIDMapper or m_pProfilersFuncIDMapper2 should not be NULL;
1065 _ASSERTE((m_pProfilersFuncIDMapper != NULL) || (m_pProfilersFuncIDMapper2 != NULL));
1067 UINT_PTR clientId = NULL;
1069 if (m_pProfilersFuncIDMapper2 != NULL)
1071 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
1073 "**PROF: Calling profiler's FunctionIDMapper2. funcId: 0x%p. clientData: 0x%p.\n",
1075 m_pProfilersFuncIDMapper2ClientData));
1077 // The attached profiler may not want to hook this function, so ask it
1078 clientId = m_pProfilersFuncIDMapper2(funcId, m_pProfilersFuncIDMapper2ClientData, pbHookFunction);
1083 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
1085 "**PROF: Calling profiler's FunctionIDMapper. funcId: 0x%p.\n",
1088 // The attached profiler may not want to hook this function, so ask it
1089 clientId = m_pProfilersFuncIDMapper(funcId, pbHookFunction);
1092 static LONG s_lIsELT2Enabled = -1;
1093 if (s_lIsELT2Enabled == -1)
1095 LONG lEnabled = ((m_pEnter2 != NULL) ||
1096 (m_pLeave2 != NULL) ||
1097 (m_pTailcall2 != NULL));
1099 InterlockedCompareExchange(&s_lIsELT2Enabled, lEnabled, -1);
1102 // We need to keep track the mapping between ClientID and FunctionID for ELT2
1103 if (s_lIsELT2Enabled != 0)
1105 FunctionIDAndClientID functionIDAndClientID;
1106 functionIDAndClientID.functionID = funcId;
1107 functionIDAndClientID.clientID = clientId;
1109 // ClientID Hash table may throw OUTOFMEMORY exception, which is not expected by the caller.
1112 SimpleWriteLockHolder writeLockHolder(m_pFunctionIDHashTableRWLock);
1113 m_pFunctionIDHashTable->AddOrReplace(functionIDAndClientID);
1117 // Running out of heap memory means we no longer can maintain the integrity of the mapping table.
1118 // All ELT2 fast-path hooks are disabled since we cannot report correct FunctionID to the
1119 // profiler at this moment.
1120 m_fIsClientIDToFunctionIDMappingEnabled = FALSE;
1122 EX_END_CATCH(RethrowTerminalExceptions);
1124 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
1125 // instead of using clientID because the profiler may map several functionIDs to a clientID to
1126 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
1127 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
1128 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
1132 // For profilers that support ELT3, clientID will be embedded into the ELT3 probes
1137 //---------------------------------------------------------------------------------------
1139 // Private functions called by GC so we can cache data for later notification to
1143 //---------------------------------------------------------------------------------------
1145 // Called lazily to allocate or use a recycled GCReferencesData.
1148 // GCReferencesData * requested by caller.
1151 // Uses m_csGCRefDataFreeList to find a recycleable GCReferencesData
1152 // Called by GC callbacks that need to record GC references reported
1153 // to the callbacks by the GC as the GC walks the heap.
1156 EEToProfInterfaceImpl::GCReferencesData * EEToProfInterfaceImpl::AllocateMovedReferencesData()
1162 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
1164 // We directly take m_csGCRefDataFreeList around accessing the free list below
1167 // Thread store lock normally held during this call
1171 GCReferencesData *pData = NULL;
1173 // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1175 CRITSEC_Holder csh(m_csGCRefDataFreeList);
1177 // Anything on the free list for us to grab?
1178 if (m_pGCRefDataFreeList != NULL)
1180 // Yup, get the first element from the free list
1181 pData = m_pGCRefDataFreeList;
1182 m_pGCRefDataFreeList = m_pGCRefDataFreeList->pNext;
1188 // Still not set, so the free list must not have had anything
1189 // available. Go ahead and allocate a struct directly.
1190 pData = new (nothrow) GCReferencesData;
1197 // Now init the new block
1198 _ASSERTE(pData != NULL);
1200 // Set our index to the beginning
1202 pData->compactingCount = 0;
1207 //---------------------------------------------------------------------------------------
1209 // After reporting references to the profiler, this recycles the GCReferencesData
1210 // that was used. See EEToProfInterfaceImpl::EndRootReferences2.
1213 // pData - Pointer to GCReferencesData to recycle
1216 void EEToProfInterfaceImpl::FreeMovedReferencesData(GCReferencesData * pData)
1224 // We directly take m_csGCRefDataFreeList around accessing the free list below
1227 // Thread store lock normally held during this callback
1232 // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1234 CRITSEC_Holder csh(m_csGCRefDataFreeList);
1235 pData->pNext = m_pGCRefDataFreeList;
1236 m_pGCRefDataFreeList = pData;
1240 //---------------------------------------------------------------------------------------
1242 // Called by the GC to notify profapi of a moved reference. We cache the
1243 // info here so we can later notify the profiler of all moved references
1247 // pbMemBlockStart - Start of moved block
1248 // pbMemBlockEnd - End of moved block
1249 // cbRelocDistance - Offset from pbMemBlockStart of where the block
1251 // pHeapId - GCReferencesData * used to record the block
1252 // fCompacting - Is this a compacting collection?
1255 // HRESULT indicating success or failure
1258 HRESULT EEToProfInterfaceImpl::MovedReference(BYTE * pbMemBlockStart,
1259 BYTE * pbMemBlockEnd,
1260 ptrdiff_t cbRelocDistance,
1268 // Called during a GC
1270 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
1272 // Thread store lock normally held during this callback
1277 _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1279 // Get a pointer to the data for this heap
1280 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1282 // If this is the first notification of a moved reference for this heap
1283 // in this particular gc activation, then we need to get a ref data block
1284 // from the free list of blocks, or if that's empty then we need to
1285 // allocate a new one.
1288 pData = AllocateMovedReferencesData();
1291 return E_OUTOFMEMORY;
1294 // Set the cookie so that we will be provided it on subsequent
1296 ((*((size_t *)pHeapId))) = (size_t)pData;
1299 _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1301 // If the struct has been filled, then we need to notify the profiler of
1302 // these moved references and clear the struct for the next load of
1304 if (pData->curIdx == kcReferencesMax)
1306 MovedReferences(pData);
1308 pData->compactingCount = 0;
1311 // Now save the information in the struct
1312 pData->arrpbMemBlockStartOld[pData->curIdx] = pbMemBlockStart;
1313 pData->arrpbMemBlockStartNew[pData->curIdx] = pbMemBlockStart + cbRelocDistance;
1314 pData->arrMemBlockSize[pData->curIdx] = pbMemBlockEnd - pbMemBlockStart;
1316 // Increment the index into the parallel arrays
1319 // Keep track of whether this is a compacting collection
1322 pData->compactingCount += 1;
1323 // The gc is supposed to make up its mind whether this is a compacting collection or not
1324 // Thus if this one is compacting, everything so far had to say compacting
1325 _ASSERTE(pData->compactingCount == pData->curIdx);
1329 // The gc is supposed to make up its mind whether this is a compacting collection or not
1330 // Thus if this one is non-compacting, everything so far had to say non-compacting
1331 _ASSERTE(pData->compactingCount == 0 && cbRelocDistance == 0);
1336 //---------------------------------------------------------------------------------------
1338 // Called by the GC to indicate that the GC is finished calling
1339 // EEToProfInterfaceImpl::MovedReference for this collection. This function will
1340 // call into the profiler to notify it of all the moved references we've cached.
1343 // pHeapId - Casted to a GCReferencesData * that contains the moved reference
1344 // data we've cached.
1347 // HRESULT indicating success or failure.
1350 HRESULT EEToProfInterfaceImpl::EndMovedReferences(void * pHeapId)
1356 // Called during a GC
1358 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
1360 // We directly take m_csGCRefDataFreeList around accessing the free list below
1363 // Thread store lock normally held during this callback
1368 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1372 // Get a pointer to the data for this heap
1373 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1375 // If there were no moved references, profiler doesn't need to know
1379 // Communicate the moved references to the profiler
1380 _ASSERTE(pData->curIdx> 0);
1381 hr = MovedReferences(pData);
1383 // Now we're done with the data block, we can shove it onto the free list
1384 // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1386 CRITSEC_Holder csh(m_csGCRefDataFreeList);
1387 pData->pNext = m_pGCRefDataFreeList;
1388 m_pGCRefDataFreeList = pData;
1392 // Set the cookie to an invalid number
1393 (*((size_t *)pHeapId)) = (size_t)(-1);
1400 #define HASH_ARRAY_SIZE_INITIAL 1024
1401 #define HASH_ARRAY_SIZE_INC 256
1402 #define HASH_NUM_BUCKETS 32
1403 #define HASH(x) ( (ULONG) ((SIZE_T)x) ) // A simple hash function
1405 //---------------------------------------------------------------------------------------
1407 // Callback used by the GC when walking the heap (via AllocByClassHelper in
1408 // ProfToEEInterfaceImpl.cpp).
1411 // objId - Object reference encountered during heap walk
1412 // classId - ClassID for objID
1413 // pHeapId - heap walk context used by this function; it's interpreted
1414 // as an AllocByClassData * to keep track of objects on the
1418 // HRESULT indicating whether to continue with the heap walk (i.e.,
1419 // success HRESULT) or abort it (i.e., failure HRESULT).
1422 HRESULT EEToProfInterfaceImpl::AllocByClass(ObjectID objId, ClassID clsId, void * pHeapId)
1434 // This is a slight attempt to make sure that this is never called in a multi-threaded
1435 // manner. This heap walk should be done by one thread at a time only.
1436 static DWORD dwProcId = 0xFFFFFFFF;
1439 _ASSERTE(pHeapId != NULL);
1440 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1442 // The heapId they pass in is really a AllocByClassData struct ptr.
1443 AllocByClassData *pData = (AllocByClassData *)(*((size_t *)pHeapId));
1445 // If it's null, need to allocate one
1449 // This is a slight attempt to make sure that this is never called in a multi-threaded
1450 // manner. This heap walk should be done by one thread at a time only.
1451 dwProcId = GetCurrentProcessId();
1454 // See if we've saved a data block from a previous GC
1455 if (m_pSavedAllocDataBlock != NULL)
1456 pData = m_pSavedAllocDataBlock;
1458 // This means we need to allocate all the memory to keep track of the info
1461 // Get a new alloc data block
1462 pData = new (nothrow) AllocByClassData;
1464 return (E_OUTOFMEMORY);
1466 // Create a new hash table
1467 pData->pHashTable = new (nothrow) CHashTableImpl(HASH_NUM_BUCKETS);
1468 if (!pData->pHashTable)
1471 return (E_OUTOFMEMORY);
1474 // Get the memory for the array that the hash table is going to use
1475 pData->arrHash = new (nothrow) CLASSHASHENTRY[HASH_ARRAY_SIZE_INITIAL];
1476 if (pData->arrHash == NULL)
1478 delete pData->pHashTable;
1480 return (E_OUTOFMEMORY);
1483 // Save the number of elements in the array
1484 pData->cHash = HASH_ARRAY_SIZE_INITIAL;
1486 // Now initialize the hash table
1487 HRESULT hr = pData->pHashTable->NewInit((BYTE *)pData->arrHash, sizeof(CLASSHASHENTRY));
1488 if (hr == E_OUTOFMEMORY)
1490 delete [] pData->arrHash;
1491 delete pData->pHashTable;
1493 return (E_OUTOFMEMORY);
1495 _ASSERTE(pData->pHashTable->IsInited());
1497 // Null some entries
1498 pData->arrClsId = NULL;
1499 pData->arrcObjects = NULL;
1502 // Hold on to the structure
1503 m_pSavedAllocDataBlock = pData;
1506 // Got some memory and hash table to store entries, yay!
1507 *((size_t *)pHeapId) = (size_t)pData;
1509 // Initialize the data
1511 pData->pHashTable->Clear();
1514 _ASSERTE(pData->iHash <= pData->cHash);
1515 _ASSERTE(dwProcId == GetCurrentProcessId());
1517 // Lookup to see if this class already has an entry
1518 CLASSHASHENTRY * pEntry =
1519 reinterpret_cast<CLASSHASHENTRY *>(pData->pHashTable->Find(HASH(clsId), (SIZE_T)clsId));
1521 // If this class has already been encountered, just increment the counter.
1525 // Otherwise, need to add this one as a new entry in the hash table
1528 // If we're full, we need to realloc
1529 if (pData->iHash == pData->cHash)
1531 // Try to realloc the memory
1532 CLASSHASHENTRY *tmp = new (nothrow) CLASSHASHENTRY[pData->cHash + HASH_ARRAY_SIZE_INC];
1535 return (E_OUTOFMEMORY);
1538 _ASSERTE(pData->arrHash);
1539 memcpy (tmp, pData->arrHash, pData->cHash*sizeof(CLASSHASHENTRY));
1540 delete [] pData->arrHash;
1541 pData->arrHash = tmp;
1542 // Tell the hash table that the memory location of the array has changed
1543 pData->pHashTable->SetTable((BYTE *)pData->arrHash);
1545 // Save the new size of the array
1546 pData->cHash += HASH_ARRAY_SIZE_INC;
1549 // Now add the new entry
1550 CLASSHASHENTRY *pNewEntry = (CLASSHASHENTRY *) pData->pHashTable->Add(HASH(clsId), pData->iHash++);
1552 pNewEntry->m_clsId = clsId;
1553 pNewEntry->m_count = 1;
1560 HRESULT EEToProfInterfaceImpl::EndAllocByClass(void *pHeapId)
1562 _ASSERTE(pHeapId != NULL);
1563 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1567 AllocByClassData *pData = (AllocByClassData *)(*((size_t *)pHeapId));
1569 // Notify the profiler if there are elements to notify it of
1571 hr = NotifyAllocByClass(pData);
1574 (*((size_t *)pHeapId)) = (size_t)(-1);
1580 //---------------------------------------------------------------------------------------
1582 // Convert ETW-style root flag bitmask to ProfAPI-stye root flag bitmask
1585 // dwEtwRootFlags - ETW-style root flag bitmask
1588 // The corresponding ProfAPI-stye root flag bitmask
1591 DWORD EtwRootFlagsToProfApiRootFlags(DWORD dwEtwRootFlags)
1593 LIMITED_METHOD_CONTRACT;
1595 // If a new ETW flag is added, adjust this assert, and add a case below.
1596 _ASSERTE((dwEtwRootFlags &
1597 ~(kEtwGCRootFlagsPinning | kEtwGCRootFlagsWeakRef | kEtwGCRootFlagsInterior | kEtwGCRootFlagsRefCounted))
1600 DWORD dwProfApiRootFlags = 0;
1602 if ((dwEtwRootFlags & kEtwGCRootFlagsPinning) != 0)
1604 dwProfApiRootFlags |= COR_PRF_GC_ROOT_PINNING;
1606 if ((dwEtwRootFlags & kEtwGCRootFlagsWeakRef) != 0)
1608 dwProfApiRootFlags |= COR_PRF_GC_ROOT_WEAKREF;
1610 if ((dwEtwRootFlags & kEtwGCRootFlagsInterior) != 0)
1612 dwProfApiRootFlags |= COR_PRF_GC_ROOT_INTERIOR;
1614 if ((dwEtwRootFlags & kEtwGCRootFlagsRefCounted) != 0)
1616 dwProfApiRootFlags |= COR_PRF_GC_ROOT_REFCOUNTED;
1618 return dwProfApiRootFlags;
1621 //---------------------------------------------------------------------------------------
1623 // Convert ETW-style root kind enum to ProfAPI-stye root kind enum
1626 // dwEtwRootKind - ETW-style root kind enum
1629 // Corresponding ProfAPI-stye root kind enum
1632 DWORD EtwRootKindToProfApiRootKind(EtwGCRootKind dwEtwRootKind)
1634 LIMITED_METHOD_CONTRACT;
1636 switch(dwEtwRootKind)
1639 // If a new ETW root kind is added, create a profapi root kind as well, and add
1640 // the appropriate case below
1641 _ASSERTE(!"Unrecognized ETW root kind");
1642 // Deliberately fall through to kEtwGCRootKindOther
1644 case kEtwGCRootKindOther:
1645 return COR_PRF_GC_ROOT_OTHER;
1647 case kEtwGCRootKindStack:
1648 return COR_PRF_GC_ROOT_STACK;
1650 case kEtwGCRootKindFinalizer:
1651 return COR_PRF_GC_ROOT_FINALIZER;
1653 case kEtwGCRootKindHandle:
1654 return COR_PRF_GC_ROOT_HANDLE;
1658 //---------------------------------------------------------------------------------------
1660 // Callback used by the GC when scanning the roots (via ScanRootsHelper in
1661 // ProfToEEInterfaceImpl.cpp).
1664 // objectId - Root object reference encountered
1665 // dwEtwRootKind - ETW enum describing what kind of root objectId is
1666 // dwEtwRootFlags - ETW flags describing the root qualities of objectId
1667 // rootID - Root's methoddesc if dwEtwRootKind==kEtwGCRootKindStack, else NULL
1668 // pHeapId - Used as a GCReferencesData * to keep track of the GC references
1671 // HRESULT indicating success or failure.
1674 HRESULT EEToProfInterfaceImpl::RootReference2(BYTE * objectId,
1675 EtwGCRootKind dwEtwRootKind,
1676 EtwGCRootFlags dwEtwRootFlags,
1681 _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1683 LOG((LF_CORPROF, LL_INFO100000, "**PROF: Root Reference. "
1684 "ObjectID:0x%p dwEtwRootKind:0x%x dwEtwRootFlags:0x%x rootId:0x%p HeadId:0x%p\n",
1685 objectId, dwEtwRootKind, dwEtwRootFlags, rootID, pHeapId));
1687 DWORD dwProfApiRootFlags = EtwRootFlagsToProfApiRootFlags(dwEtwRootFlags);
1688 DWORD dwProfApiRootKind = EtwRootKindToProfApiRootKind((EtwGCRootKind) dwEtwRootKind);
1690 // Get a pointer to the data for this heap
1691 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1693 // If this is the first notification of an extended root reference for this heap
1694 // in this particular gc activation, then we need to get a ref data block
1695 // from the free list of blocks, or if that's empty then we need to
1696 // allocate a new one.
1699 pData = AllocateMovedReferencesData();
1701 return (E_OUTOFMEMORY);
1703 // Set the cookie so that we will be provided it on subsequent
1705 ((*((size_t *)pHeapId))) = (size_t)pData;
1708 _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1710 // If the struct has been filled, then we need to notify the profiler of
1711 // these root references and clear the struct for the next load of
1713 if (pData->curIdx == kcReferencesMax)
1715 RootReferences2(pData);
1719 // Now save the information in the struct
1720 pData->arrpbMemBlockStartOld[pData->curIdx] = objectId;
1721 pData->arrpbMemBlockStartNew[pData->curIdx] = (BYTE *)rootID;
1723 // assert that dwProfApiRootKind and dwProfApiRootFlags both fit in 16 bits, so we can
1724 // pack both into a 32-bit word
1725 _ASSERTE((dwProfApiRootKind & 0xffff) == dwProfApiRootKind && (dwProfApiRootFlags & 0xffff) == dwProfApiRootFlags);
1727 pData->arrULONG[pData->curIdx] = (dwProfApiRootKind << 16) | dwProfApiRootFlags;
1729 // Increment the index into the parallel arrays
1735 //---------------------------------------------------------------------------------------
1737 // Called by the GC to indicate that the GC is finished calling
1738 // EEToProfInterfaceImpl::RootReference2 for this collection. This function will
1739 // call into the profiler to notify it of all the root references we've cached.
1742 // pHeapId - Casted to a GCReferencesData * that contains the root references
1746 // HRESULT indicating success or failure.
1749 HRESULT EEToProfInterfaceImpl::EndRootReferences2(void * pHeapId)
1752 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1756 // Get a pointer to the data for this heap
1757 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1759 // If there were no moved references, profiler doesn't need to know
1763 // Communicate the moved references to the profiler
1764 _ASSERTE(pData->curIdx> 0);
1765 hr = RootReferences2(pData);
1767 // Now we're done with the data block, we can shove it onto the free list
1768 FreeMovedReferencesData(pData);
1771 // Set the cookie to an invalid number
1772 (*((size_t *)pHeapId)) = (size_t)(-1);
1778 //---------------------------------------------------------------------------------------
1780 // Callback used by the GC when scanning the roots (via
1781 // Ref_ScanDependentHandlesForProfilerAndETW in ObjectHandle.cpp).
1784 // primaryObjectId - Primary object reference in the DependentHandle
1785 // secondaryObjectId - Secondary object reference in the DependentHandle
1786 // rootID - The DependentHandle maintaining the dependency relationship
1787 // pHeapId - Used as a GCReferencesData * to keep track of the GC references
1790 // HRESULT indicating success or failure.
1793 HRESULT EEToProfInterfaceImpl::ConditionalWeakTableElementReference(BYTE * primaryObjectId,
1794 BYTE * secondaryObjectId,
1799 _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1801 // Callers must ensure the profiler asked to be notified about dependent handles,
1802 // since this is only available for profilers implementing ICorProfilerCallback5 and
1804 _ASSERTE(CORProfilerTrackConditionalWeakTableElements());
1806 LOG((LF_CORPROF, LL_INFO100000, "**PROF: Root Dependent Handle. "
1807 "PrimaryObjectID:0x%p SecondaryObjectID:0x%p rootId:0x%p HeadId:0x%p\n",
1808 primaryObjectId, secondaryObjectId, rootID, pHeapId));
1810 // Get a pointer to the data for this heap
1811 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1813 // If this is the first notification of a dependent handle reference in
1814 // this particular gc activation, then we need to get a ref data block
1815 // from the free list of blocks, or if that's empty then we need to
1816 // allocate a new one.
1819 pData = AllocateMovedReferencesData();
1821 return (E_OUTOFMEMORY);
1823 // Set the cookie so that we will be provided it on subsequent
1825 ((*((size_t *)pHeapId))) = (size_t)pData;
1828 _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1830 // If the struct has been filled, then we need to notify the profiler of
1831 // these dependent handle references and clear the struct for the next
1832 // load of dependent handle references
1833 if (pData->curIdx == kcReferencesMax)
1835 ConditionalWeakTableElementReferences(pData);
1839 // Now save the information in the struct
1840 pData->arrpbMemBlockStartOld[pData->curIdx] = primaryObjectId;
1841 pData->arrpbMemBlockStartNew[pData->curIdx] = secondaryObjectId;
1842 pData->arrpbRootId[pData->curIdx] = (BYTE*) rootID;
1844 // Increment the index into the parallel arrays
1850 //---------------------------------------------------------------------------------------
1852 // Called by the GC to indicate that the GC is finished calling
1853 // EEToProfInterfaceImpl::ConditionalWeakTableElementReference for this collection. This
1854 // function will call into the profiler to notify it of all the DependentHandle references
1858 // pHeapId - Casted to a GCReferencesData * that contains the dependent handle
1859 // references we've cached.
1862 // HRESULT indicating success or failure.
1865 HRESULT EEToProfInterfaceImpl::EndConditionalWeakTableElementReferences(void * pHeapId)
1868 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1870 // Callers must ensure the profiler asked to be notified about dependent handles,
1871 // since this is only available for profilers implementing ICorProfilerCallback5 and
1873 _ASSERTE(CORProfilerTrackConditionalWeakTableElements());
1877 // Get a pointer to the data for this heap
1878 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1880 // If there were no dependent handles, profiler doesn't need to know
1884 // Communicate the dependent handle references to the profiler
1885 _ASSERTE(pData->curIdx > 0);
1886 hr = ConditionalWeakTableElementReferences(pData);
1888 // Now we're done with the data block, we can shove it onto the free list
1889 FreeMovedReferencesData(pData);
1892 // Set the cookie to an invalid number
1893 (*((size_t *)pHeapId)) = (size_t)(-1);
1901 //---------------------------------------------------------------------------------------
1903 // Returns whether the profiler performed unrevertible acts, such as instrumenting
1904 // code or requesting ELT hooks. RequestProfilerDetach uses this function before
1905 // performing any sealing or evacuation checks to determine whether it's even possible
1906 // for the profiler ever to detach.
1909 // * S_OK if it's safe to attempt a detach. Evacuation checks must still be performed
1910 // before actually unloading the profiler.
1911 // * else, an HRESULT error value indicating what the profiler did that made it
1912 // undetachable. This is a public HRESULT suitable for returning from the
1913 // RequestProfilerDetach API.
1916 HRESULT EEToProfInterfaceImpl::EnsureProfilerDetachable()
1918 LIMITED_METHOD_CONTRACT;
1920 if ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE) != 0)
1925 "**PROF: Profiler may not detach because it set an immutable flag. Flags = 0x%x.\n",
1926 g_profControlBlock.dwEventMask));
1928 return CORPROF_E_IMMUTABLE_FLAGS_SET;
1931 if ((m_pEnter != NULL) ||
1932 (m_pLeave != NULL) ||
1933 (m_pTailcall != NULL) ||
1934 (m_pEnter2 != NULL) ||
1935 (m_pLeave2 != NULL) ||
1936 (m_pTailcall2 != NULL) ||
1937 (m_pEnter3 != NULL) ||
1938 (m_pEnter3WithInfo != NULL) ||
1939 (m_pLeave3 != NULL) ||
1940 (m_pLeave3WithInfo != NULL) ||
1941 (m_pTailcall3 != NULL) ||
1942 (m_pTailcall3WithInfo != NULL))
1947 "**PROF: Profiler may not detach because it set an ELT(2) hook.\n"));
1949 return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;
1952 if (m_fUnrevertiblyModifiedIL)
1957 "**PROF: Profiler may not detach because it called SetILFunctionBody.\n"));
1959 return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;
1965 // Declarations for asm wrappers of profiler callbacks
1966 EXTERN_C void __stdcall ProfileEnterNaked(FunctionIDOrClientID functionIDOrClientID);
1967 EXTERN_C void __stdcall ProfileLeaveNaked(FunctionIDOrClientID functionIDOrClientID);
1968 EXTERN_C void __stdcall ProfileTailcallNaked(FunctionIDOrClientID functionIDOrClientID);
1969 #define PROFILECALLBACK(name) name##Naked
1971 //---------------------------------------------------------------------------------------
1973 // Determines the hooks (slow path vs. fast path) to which the JIT shall
1974 // insert calls, and then tells the JIT which ones we want
1977 // HRESULT indicating success or failure
1980 HRESULT EEToProfInterfaceImpl::DetermineAndSetEnterLeaveFunctionHooksForJit()
1991 // We're doing all ELT3 hooks, all-Whidbey hooks or all-Everett hooks. No mixing and matching.
1992 BOOL fCLRv4Hooks = (m_pEnter3 != NULL) ||
1993 (m_pLeave3 != NULL) ||
1994 (m_pTailcall3 != NULL) ||
1995 (m_pEnter3WithInfo != NULL) ||
1996 (m_pLeave3WithInfo != NULL) ||
1997 (m_pTailcall3WithInfo != NULL);
1999 BOOL fWhidbeyHooks = (m_pEnter2 != NULL) ||
2000 (m_pLeave2 != NULL) ||
2001 (m_pTailcall2 != NULL);
2003 // If no hooks were set (e.g., SetEventMask called with COR_PRF_MONITOR_ENTERLEAVE,
2004 // but SetEnterLeaveFunctionHooks(*) never called), then nothing to do
2007 (m_pEnter == NULL) &&
2008 (m_pLeave == NULL) &&
2009 (m_pTailcall == NULL))
2021 // For each type of hook (enter/leave/tailcall) we must determine if we can use the
2022 // happy lucky fast path (i.e., direct call from JITd code right into the profiler's
2023 // hook or the JIT default stub (see below)), or the slow path (i.e., call into an
2024 // intermediary FCALL which then calls the profiler's hook) with extra information
2025 // about the current function.
2027 // The casts below are to appease rotor. cl.exe doesn't need them.
2028 hr = SetEnterLeaveFunctionHooksForJit(
2029 (m_pEnter3WithInfo != NULL) ?
2030 reinterpret_cast<FunctionEnter3 *>(PROFILECALLBACK(ProfileEnter)) :
2032 (m_pLeave3WithInfo != NULL) ?
2033 reinterpret_cast<FunctionLeave3 *>(PROFILECALLBACK(ProfileLeave)) :
2035 (m_pTailcall3WithInfo != NULL) ?
2036 reinterpret_cast<FunctionTailcall3 *>(PROFILECALLBACK(ProfileTailcall)) :
2042 // Everett or Whidbey hooks.
2045 // When using Everett or Whidbey hooks, the check looks like this:
2048 // THEN Use slow path
2052 // - If the profiler wants the old-style Whidbey or Everett hooks, we need a wrapper
2053 // to convert from the ELT3 prototype the JIT expects to the Whidbey or Everett
2054 // prototype the profiler expects. It applies to Whidbey fast-path hooks. And due
2055 // to the overhead of looking up FunctionID from cache and using lock to synchronize
2056 // cache accesses, the so-called Whidbey fast-path hooks are much slower than they
2057 // used to be. Whidbey and Everett hooks are supported to keep existing profiler
2058 // running, but the profiler writers are encouraged to use ELT3 interface for the
2059 // best performance.
2061 // Implicit in the above logic is if one of the hook types has no hook pointer
2062 // specified, then we pass NULL as the hook pointer to the JIT, in which case the JIT
2063 // just generates a call to the default stub (a single ret) w/out invoking the slow-path
2064 // wrapper. I call this the "fast path to nowhere"
2066 BOOL fEnter = (m_pEnter != NULL) || (m_pEnter2 != NULL);
2067 BOOL fLeave = (m_pLeave != NULL) || (m_pLeave2 != NULL);
2068 BOOL fTailcall = (m_pTailcall != NULL) || (m_pTailcall2 != NULL);
2070 // The casts below are to appease rotor. cl.exe doesn't need them.
2071 hr = SetEnterLeaveFunctionHooksForJit(
2073 reinterpret_cast<FunctionEnter3 *>(PROFILECALLBACK(ProfileEnter)) :
2076 reinterpret_cast<FunctionLeave3 *>(PROFILECALLBACK(ProfileLeave)) :
2079 reinterpret_cast<FunctionTailcall3 *>(PROFILECALLBACK(ProfileTailcall)) :
2087 // We need to swallow all exceptions, because we will lock otherwise (in addition to
2088 // the IA64-only lock while allocating stub space!). For example, specifying
2089 // RethrowTerminalExceptions forces us to test to see if the caught exception is
2090 // terminal and Exception::IsTerminal() can lock if we get a handle table cache miss
2091 // while getting a handle for the exception. It is good to minimize locks from
2092 // profiler Info functions (and their callees), and this is a dumb lock to have,
2093 // given that we can avoid it altogether by just having terminal exceptions be
2094 // swallowed here, and returning the failure to the profiler. For those who don't
2095 // like swallowing terminal exceptions, this is mitigated by the fact that,
2096 // currently, an exception only gets thrown from SetEnterLeaveFunctionHooksForJit on
2097 // IA64. But to keep consistent (and in case the world changes), we'll do this on
2099 EX_END_CATCH(SwallowAllExceptions);
2105 //---------------------------------------------------------------------------------------
2107 // The Info method SetEventMask() simply defers to this function to do the real work.
2110 // dwEventMask - Event mask specified by the profiler
2113 // HRESULT indicating success / failure to return straight through to the profiler
2116 HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMaskHigh)
2123 EE_THREAD_NOT_REQUIRED;
2129 static const DWORD kEventFlagsRequiringSlowPathEnterLeaveHooks =
2130 COR_PRF_ENABLE_FUNCTION_ARGS |
2131 COR_PRF_ENABLE_FUNCTION_RETVAL |
2132 COR_PRF_ENABLE_FRAME_INFO
2135 static const DWORD kEventFlagsAffectingEnterLeaveHooks =
2136 COR_PRF_MONITOR_ENTERLEAVE |
2137 kEventFlagsRequiringSlowPathEnterLeaveHooks
2143 // Some tests need to enable immutable flags after startup, when a profiler is
2144 // attached. These flags enable features that are used solely to verify the
2145 // correctness of other, MUTABLE features. Examples: enable immutable ELT to create
2146 // shadow stacks to verify stack walks (which can be done mutably via manual
2147 // EBP-frame walking), or enable immutable DSS to gather IP addresses to verify the
2148 // mutable GetFunctionFromIP.
2150 // Similarly, test profilers may need to extend the set of flags allowable on attach
2151 // to enable features that help verify other parts of the profapi that ARE allowed
2154 // See code:#P2CLRRestrictionsOverview for more information
2155 DWORD dwImmutableEventFlags = COR_PRF_MONITOR_IMMUTABLE;
2156 DWORD dwAllowableAfterAttachEventFlags = COR_PRF_ALLOWABLE_AFTER_ATTACH;
2157 DWORD dwTestOnlyAllowedEventMask = 0;
2158 dwTestOnlyAllowedEventMask = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TestOnlyAllowedEventMask);
2159 if (dwTestOnlyAllowedEventMask != 0)
2161 // Remove from the immutable flag list those flags that a test-only profiler may
2162 // need to set post-startup (specified via COMPlus_TestOnlyAllowedEventMask)
2163 dwImmutableEventFlags &= ~dwTestOnlyAllowedEventMask;
2165 // And add to the "allowable after attach" list the same test-only flags.
2166 dwAllowableAfterAttachEventFlags |= dwTestOnlyAllowedEventMask;
2168 LOG((LF_CORPROF, LL_INFO10, "**PROF: TestOnlyAllowedEventMask=0x%x. New immutable flags=0x%x. New AllowableAfterAttach flags=0x%x\n",
2169 dwTestOnlyAllowedEventMask,
2170 dwImmutableEventFlags,
2171 dwAllowableAfterAttachEventFlags));
2175 // If we're not in initialization or shutdown, make sure profiler is
2176 // not trying to set an immutable attribute
2177 // FUTURE: If we add immutable flags to the high event mask, this would be a good
2178 // place to check for them as well.
2179 if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
2182 if ((dwEventMask & dwImmutableEventFlags) !=
2183 (g_profControlBlock.dwEventMask & dwImmutableEventFlags))
2185 if ((dwEventMask & COR_PRF_MONITOR_IMMUTABLE) !=
2186 (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE))
2189 // FUTURE: Should we have a dedicated HRESULT for setting immutable flag?
2194 // If this is an attaching profiler, make sure the profiler only sets flags
2195 // allowable after an attach
2196 if (m_fLoadedViaAttach &&
2198 ((dwEventMask & (~dwAllowableAfterAttachEventFlags)) != 0))
2200 ((dwEventMask & (~COR_PRF_ALLOWABLE_AFTER_ATTACH)) != 0))
2203 return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER;
2206 // After fast path ELT hooks are set in Initial callback, the startup profiler is not allowed to change flags
2207 // that require slow path ELT hooks or disable ELT hooks.
2208 if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
2210 (m_pEnter3 != NULL) ||
2211 (m_pLeave3 != NULL) ||
2212 (m_pTailcall3 != NULL)
2215 ((dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0) ||
2216 ((dwEventMask & COR_PRF_MONITOR_ENTERLEAVE) == 0)
2220 _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0);
2221 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2224 // After slow path ELT hooks are set in Initial callback, the startup profiler is not allowed to remove
2225 // all flags that require slow path ELT hooks or to change the flag to disable the ELT hooks.
2226 if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
2228 (m_pEnter3WithInfo != NULL) ||
2229 (m_pLeave3WithInfo != NULL) ||
2230 (m_pTailcall3WithInfo != NULL)
2233 ((dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0) ||
2234 ((dwEventMask & COR_PRF_MONITOR_ENTERLEAVE) == 0)
2238 _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0);
2239 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2243 // Note whether the caller is changing flags that affect enter leave hooks
2244 BOOL fEnterLeaveHooksAffected =
2245 // Did any of the relevant flags change?
2249 ((g_profControlBlock.dwEventMask & kEventFlagsAffectingEnterLeaveHooks) ^
2250 // XORed w/ the new flags
2251 (dwEventMask & kEventFlagsAffectingEnterLeaveHooks))
2254 // And are any enter/leave hooks set?
2256 (m_pEnter3 != NULL) ||
2257 (m_pEnter3WithInfo != NULL) ||
2258 (m_pEnter2 != NULL) ||
2259 (m_pEnter != NULL) ||
2260 (m_pLeave3 != NULL) ||
2261 (m_pLeave3WithInfo != NULL) ||
2262 (m_pLeave2 != NULL) ||
2263 (m_pLeave != NULL) ||
2264 (m_pTailcall3 != NULL) ||
2265 (m_pTailcall3WithInfo != NULL) ||
2266 (m_pTailcall2 != NULL) ||
2267 (m_pTailcall != NULL)
2270 BOOL fNeedToTurnOffConcurrentGC = FALSE;
2272 if (((dwEventMask & COR_PRF_MONITOR_GC) != 0) &&
2273 ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_GC) == 0))
2275 // We don't need to worry about startup load as we'll turn off concurrent GC later
2276 if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
2278 // Since we're not an initializing startup profiler, the EE must be fully started up
2279 // so we can check whether concurrent GC is on
2282 return CORPROF_E_RUNTIME_UNINITIALIZED;
2285 // We don't want to change the flag before GC is fully initialized,
2286 // otherwise the concurrent GC setting would be overwritten
2287 // Make sure GC is fully initialized before proceed
2288 if (!IsGarbageCollectorFullyInitialized())
2290 return CORPROF_E_NOT_YET_AVAILABLE;
2293 // If we are attaching and we are turning on COR_PRF_MONITOR_GC, turn off concurrent GC later
2295 if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForAttachLoad)
2297 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled())
2299 // We only allow turning off concurrent GC in the profiler attach thread inside
2300 // InitializeForAttach, otherwise we would be vulnerable to weird races such as
2301 // SetEventMask running on a separate thread and trying to turn off concurrent GC.
2302 // The best option here is to fail with CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE.
2303 // Existing Dev10 profilers should be prepared to handle such case.
2304 if (IsProfilerAttachThread())
2306 fNeedToTurnOffConcurrentGC = TRUE;
2310 return CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE;
2316 // Fail if concurrent GC is enabled
2317 // This should only happen for attach profilers if user didn't turn on COR_PRF_MONITOR_GC
2319 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled())
2321 return CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE;
2327 // Flags defined in COR_PRF_REQUIRE_PROFILE_IMAGE will force to JIT mscorlib if the
2328 // user does not ngen mscorlib with /profiler. Similarly, the
2329 // COR_PRF_DISABLE_ALL_NGEN_IMAGES flag always forces us to JIT mscorlib. Using the
2330 // jitted version of mscorlib with HPA(Host Protection Attributes) enabled will cause
2331 // stack overflow inside JIT. See Dev 10 Bug 637987 for the detail.
2332 if (((dwEventMask & (COR_PRF_REQUIRE_PROFILE_IMAGE | COR_PRF_DISABLE_ALL_NGEN_IMAGES)) != 0) &&
2333 (GetHostProtectionManager() != NULL) &&
2334 (GetHostProtectionManager()->GetProtectedCategories() != eNoChecks))
2336 return CORPROF_E_INCONSISTENT_FLAGS_WITH_HOST_PROTECTION_SETTING;
2341 if (((dwEventMaskHigh & COR_PRF_HIGH_ADD_ASSEMBLY_REFERENCES) != 0) &&
2342 !IsCallback6Supported())
2344 return CORPROF_E_CALLBACK6_REQUIRED;
2347 if (((dwEventMaskHigh & COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED) != 0) &&
2348 !IsCallback7Supported())
2350 return CORPROF_E_CALLBACK7_REQUIRED;
2353 // Now save the modified masks
2354 g_profControlBlock.dwEventMask = dwEventMask;
2355 g_profControlBlock.dwEventMaskHigh = dwEventMaskHigh;
2357 if (fEnterLeaveHooksAffected)
2359 hr = DetermineAndSetEnterLeaveFunctionHooksForJit();
2366 if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad)
2368 // If the profiler has requested remoting cookies so that it can
2369 // track logical call stacks, then we must initialize the cookie
2371 if ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_REMOTING_COOKIE)
2372 == COR_PRF_MONITOR_REMOTING_COOKIE)
2382 // Turn off concurrent GC as the last step so that we don't need to turn it back on if something
2383 // else failed after that
2384 if (fNeedToTurnOffConcurrentGC)
2386 // Turn off concurrent GC if it is on so that user can walk the heap safely in GC callbacks
2387 IGCHeap * pGCHeap = GCHeapUtilities::GetGCHeap();
2389 LOG((LF_CORPROF, LL_INFO10, "**PROF: Turning off concurrent GC at attach.\n"));
2391 // First turn off concurrent GC
2392 pGCHeap->TemporaryDisableConcurrentGC();
2395 // Then wait until concurrent GC to finish if concurrent GC is in progress
2396 // User can use a timeout that can be set by environment variable if the GC turns out
2397 // to be too long. The default value is INFINITE.
2400 // If we don't do it in this order there might be a new concurrent GC started
2401 // before we actually turn off concurrent GC
2403 hr = pGCHeap->WaitUntilConcurrentGCCompleteAsync(m_dwConcurrentGCWaitTimeoutInMs);
2406 if (hr == HRESULT_FROM_WIN32(ERROR_TIMEOUT))
2408 // Convert it to a more specific HRESULT
2409 hr = CORPROF_E_TIMEOUT_WAITING_FOR_CONCURRENT_GC;
2411 // Since we cannot call LogProfEvent here due to contact violations, we'll need to
2412 // remember the fact that we've failed, and report the failure later after InitializeForAttach
2413 m_bHasTimedOutWaitingForConcurrentGC = TRUE;
2416 pGCHeap->TemporaryEnableConcurrentGC();
2420 // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling
2421 g_profControlBlock.fConcurrentGCDisabledForAttach = TRUE;
2423 LOG((LF_CORPROF, LL_INFO10, "**PROF: Concurrent GC has been turned off at attach.\n"));
2430 //---------------------------------------------------------------------------------------
2432 // The Info method SetEnterLeaveFunctionHooks() simply defers to this function to do the
2436 // (same as specified in the public API docs)
2439 // HRESULT indicating success / failure to return straight through to the profiler
2442 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncEnter,
2443 FunctionLeave * pFuncLeave,
2444 FunctionTailcall * pFuncTailcall)
2451 EE_THREAD_NOT_REQUIRED;
2457 // You have to be setting at least one hook
2458 if ((pFuncEnter == NULL) && (pFuncLeave == NULL) && (pFuncTailcall == NULL))
2460 return E_INVALIDARG;
2463 // ELT3 hooks beat Whidbey and Whidbey hooks beat Everett hooks. So if any ELT3 or
2464 // Whidbey hooks were set (SetEnterLeaveFunctionHooks3(WithInfo) or SetEnterLeaveFunctionHooks2),
2465 // this should be a noop
2466 if ((m_pEnter3 != NULL) ||
2467 (m_pEnter3WithInfo != NULL) ||
2468 (m_pLeave3 != NULL) ||
2469 (m_pLeave3WithInfo != NULL) ||
2470 (m_pTailcall3 != NULL) ||
2471 (m_pTailcall3WithInfo != NULL) ||
2472 (m_pEnter2 != NULL) ||
2473 (m_pLeave2 != NULL) ||
2474 (m_pTailcall2 != NULL))
2479 // Always save onto the function pointers, since we won't know if the profiler
2480 // is going to tracking enter/leave until after it returns from Initialize
2481 m_pEnter = pFuncEnter;
2482 m_pLeave = pFuncLeave;
2483 m_pTailcall = pFuncTailcall;
2485 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2488 //---------------------------------------------------------------------------------------
2490 // The Info method SetEnterLeaveFunctionHooks2() simply defers to this function to do the
2494 // (same as specified in the public API docs)
2497 // HRESULT indicating success / failure to return straight through to the profiler
2500 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFuncEnter,
2501 FunctionLeave2 * pFuncLeave,
2502 FunctionTailcall2 * pFuncTailcall)
2509 EE_THREAD_NOT_REQUIRED;
2515 // You have to be setting at least one hook
2516 if ((pFuncEnter == NULL) && (pFuncLeave == NULL) && (pFuncTailcall == NULL))
2518 return E_INVALIDARG;
2521 // ELT3 hooks beat Whidbey. So if any ELT3 hooks were set (SetEnterLeaveFunctionHooks3(WithInfo)),
2522 // this should be a noop
2523 if ((m_pEnter3 != NULL) ||
2524 (m_pEnter3WithInfo != NULL) ||
2525 (m_pLeave3 != NULL) ||
2526 (m_pLeave3WithInfo != NULL) ||
2527 (m_pTailcall3 != NULL) ||
2528 (m_pTailcall3WithInfo != NULL))
2533 // Always save onto the function pointers, since we won't know if the profiler
2534 // is going to track enter/leave until after it returns from Initialize
2535 m_pEnter2 = pFuncEnter;
2536 m_pLeave2 = pFuncLeave;
2537 m_pTailcall2 = pFuncTailcall;
2539 // Whidbey hooks override Everett hooks
2544 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2547 //---------------------------------------------------------------------------------------
2549 // The Info method SetEnterLeaveFunctionHooks3() simply defers to this function to do the
2553 // (same as specified in the public API docs)
2556 // HRESULT indicating success / failure to return straight through to the profiler
2559 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFuncEnter3,
2560 FunctionLeave3 * pFuncLeave3,
2561 FunctionTailcall3 * pFuncTailcall3)
2568 EE_THREAD_NOT_REQUIRED;
2574 // You have to be setting at least one hook
2575 if ((pFuncEnter3 == NULL) &&
2576 (pFuncLeave3 == NULL) &&
2577 (pFuncTailcall3 == NULL))
2579 return E_INVALIDARG;
2582 if (CORProfilerELT3SlowPathEnabled())
2584 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2587 // Always save onto the function pointers, since we won't know if the profiler
2588 // is going to track enter/leave until after it returns from Initialize
2589 m_pEnter3 = pFuncEnter3;
2590 m_pLeave3 = pFuncLeave3;
2591 m_pTailcall3 = pFuncTailcall3;
2592 m_pEnter3WithInfo = NULL;
2593 m_pLeave3WithInfo = NULL;
2594 m_pTailcall3WithInfo = NULL;
2596 // ELT3 hooks override Whidbey hooks and Everett hooks.
2599 m_pTailcall2 = NULL;
2604 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2608 //---------------------------------------------------------------------------------------
2610 // The Info method SetEnterLeaveFunctionHooks3() simply defers to this function to do the
2614 // (same as specified in the public API docs)
2617 // HRESULT indicating success / failure to return straight through to the profiler
2620 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter3WithInfo * pFuncEnter3WithInfo,
2621 FunctionLeave3WithInfo * pFuncLeave3WithInfo,
2622 FunctionTailcall3WithInfo * pFuncTailcall3WithInfo)
2629 EE_THREAD_NOT_REQUIRED;
2635 // You have to be setting at least one hook
2636 if ((pFuncEnter3WithInfo == NULL) &&
2637 (pFuncLeave3WithInfo == NULL) &&
2638 (pFuncTailcall3WithInfo == NULL))
2640 return E_INVALIDARG;
2643 if (!CORProfilerELT3SlowPathEnabled())
2645 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2648 // Always save onto the function pointers, since we won't know if the profiler
2649 // is going to track enter/leave until after it returns from Initialize
2650 m_pEnter3WithInfo = pFuncEnter3WithInfo;
2651 m_pLeave3WithInfo = pFuncLeave3WithInfo;
2652 m_pTailcall3WithInfo = pFuncTailcall3WithInfo;
2655 m_pTailcall3 = NULL;
2657 // ELT3 hooks override Whidbey hooks and Everett hooks.
2660 m_pTailcall2 = NULL;
2665 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2670 //---------------------------------------------------------------------------------------
2672 // ************************
2673 // Public callback wrappers
2674 // ************************
2676 // NOTE: All public callback wrappers must follow the rules stated at the top
2679 // See corprof.idl / MSDN for detailed comments about each of these public
2680 // functions, their parameters, return values, etc.
2684 //---------------------------------------------------------------------------------------
2685 // INITIALIZE CALLBACKS
2688 HRESULT EEToProfInterfaceImpl::Initialize()
2705 ASSERT_NO_EE_LOCKS_HELD();
2711 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileInitializing,
2714 "**PROF: Calling profiler's Initialize() method.\n"));
2716 _ASSERTE(m_pProfToEE != NULL);
2718 // Startup initialization occurs before an EEThread object is created for this
2720 _ASSERTE(GetThreadNULLOk() == NULL);
2723 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
2724 // whose try/catch blocks aren't visible to the contract system
2725 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
2726 return m_pCallback2->Initialize(m_pProfToEE);
2731 HRESULT EEToProfInterfaceImpl::InitializeForAttach(void * pvClientData, UINT cbClientData)
2748 ASSERT_NO_EE_LOCKS_HELD();
2754 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileInitializing,
2757 "**PROF: Calling profiler's InitializeForAttach() method.\n"));
2759 _ASSERTE(m_pProfToEE != NULL);
2761 // Attach initialization occurs on the AttachThread, which does not have an EEThread
2763 _ASSERTE(GetThreadNULLOk() == NULL);
2765 // Should only be called on profilers that support ICorProfilerCallback3
2766 _ASSERTE(m_pCallback3 != NULL);
2768 HRESULT hr = E_UNEXPECTED;
2770 // This wraps the profiler's InitializeForAttach callback in a try / catch. Although
2771 // most profiler calls are not protected, this initial callback IS, since it's cheap
2772 // to do so (this is only called once per attach of a profiler), and it would be nice to
2773 // avoid tearing down the entire process when attaching a profiler that may pass back
2777 hr = m_pCallback3->InitializeForAttach(m_pProfToEE, pvClientData, cbClientData);
2783 // Intentionally swallowing all exceptions, as we don't want a poorly-written
2784 // profiler that throws or AVs on attach to cause the entire process to go away.
2785 EX_END_CATCH(SwallowAllExceptions);
2790 HRESULT EEToProfInterfaceImpl::ProfilerAttachComplete()
2807 ASSERT_NO_EE_LOCKS_HELD();
2813 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
2815 "**PROF: Calling profiler's ProfilerAttachComplete() method.\n"));
2817 // Attach initialization occurs on the AttachThread, which does not have an EEThread
2819 _ASSERTE(GetThreadNULLOk() == NULL);
2821 // Should only be called on profilers that support ICorProfilerCallback3
2822 _ASSERTE(m_pCallback3 != NULL);
2824 HRESULT hr = E_UNEXPECTED;
2826 // This wraps the profiler's ProfilerAttachComplete callback in a try / catch.
2827 // Although most profiler calls are not protected, this early callback IS, since it's
2828 // cheap to do so (this is only called once per attach of a profiler), and it would be
2829 // nice to avoid tearing down the entire process when attaching a profiler that has
2830 // serious troubles initializing itself (e.g., in this case, with processing catch-up
2834 hr = m_pCallback3->ProfilerAttachComplete();
2840 // Intentionally swallowing all exceptions, as we don't want a poorly-written
2841 // profiler that throws or AVs on attach to cause the entire process to go away.
2842 EX_END_CATCH(SwallowAllExceptions);
2848 //---------------------------------------------------------------------------------------
2853 HRESULT EEToProfInterfaceImpl::ThreadCreated(ThreadID threadId)
2863 // Preemptive mode is particularly important here. See comment in
2864 // EEToProfInterfaceImpl::ThreadDestroyed for more information.
2871 ASSERT_NO_EE_LOCKS_HELD();
2877 // Normally these callback wrappers ask IsGCSpecial() and return without calling the
2878 // profiler if true. However, ThreadCreated() is the special case where no caller
2879 // should even get this far for GC Special threads, since our callers need to know to
2880 // avoid the GCX_PREEMP around the call to this function in the first place. See
2881 // code:Thread::m_fGCSpecial
2882 _ASSERTE(!reinterpret_cast<Thread *>(threadId)->IsGCSpecial());
2884 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId,
2887 "**PROF: Notifying profiler of created thread. ThreadId: 0x%p.\n",
2890 // Notify the profiler of the newly created thread.
2892 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
2893 // whose try/catch blocks aren't visible to the contract system
2894 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
2895 return m_pCallback2->ThreadCreated(threadId);
2899 HRESULT EEToProfInterfaceImpl::ThreadDestroyed(ThreadID threadId)
2909 // See comment below
2915 // Thread store lock is typically held during this callback
2921 if (reinterpret_cast<Thread *>(threadId)->IsGCSpecial())
2924 // In general, we like callbacks to switch to preemptive before calling into the
2925 // profiler. And this is particularly important to do in the ThreadCreated &
2926 // ThreadDestroyed callbacks.
2928 // The profiler will typically block in the ThreadDestroyed callback, because
2929 // it must coordinate the use of this threadid amongst all profiler
2930 // threads. For instance, if a separate thread A is walking "this" (via DoStackSnapshot),
2931 // then the profiler must block in ThreadDestroyed until A is finished. Otherwise,
2932 // "this" will complete its destruction before A's walk is complete.
2934 // Since the profiler will block indefinitely in ThreadDestroyed, we need
2935 // to switch to preemptive mode. Otherwise, if another thread B needs to suspend
2936 // the runtime (due to appdomain unload, GC, etc.), thread B will block
2937 // waiting for "this" (assuming we allow "this" to remain in cooperative mode),
2938 // while the profiler forces "this" to block on thread A from
2939 // the example above. And thread A may need to block on thread B, since
2940 // the stackwalking occasionally needs to switch to cooperative to access a
2941 // hash map (thus DoStackSnapshot forces the switch to cooperative up-front, before
2942 // the target thread to be walked gets suspended (yet another deadlock possibility)),
2943 // and switching to cooperative requires a wait until an in-progress GC or
2944 // EE suspension is complete. In other words, allowing "this" to remain
2945 // in cooperative mode could lead to a 3-way deadlock:
2946 // "this" waits on A
2948 // B waits on "this".
2949 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId,
2952 "**PROF: Notifying profiler of destroyed thread. ThreadId: 0x%p.\n",
2955 // From now on, issue no more callbacks for this thread
2956 SetProfilerCallbacksAllowedForThread((Thread *) threadId, FALSE);
2958 // Notify the profiler of the destroyed thread
2960 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
2961 // whose try/catch blocks aren't visible to the contract system
2962 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
2963 return m_pCallback2->ThreadDestroyed(threadId);
2967 HRESULT EEToProfInterfaceImpl::ThreadAssignedToOSThread(ThreadID managedThreadId,
2975 // Called by notrigger Thread::DetachThread & CorHost::SwitchOutLogicalThreadState
2976 // which do look to be dangerous times to be triggering a GC
2979 // This is called in notrigger zones (see above), so it's not safe to switch to preemptive
2986 ASSERT_NO_EE_LOCKS_HELD();
2992 if (reinterpret_cast<Thread *>(managedThreadId)->IsGCSpecial())
2995 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(
3000 "**PROF: Notifying profiler of thread assignment. ThreadId: 0x%p, OSThreadId: 0x%08x\n",
3004 // Notify the profiler of the thread being assigned to the OS thread
3006 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3007 // whose try/catch blocks aren't visible to the contract system
3008 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3009 return m_pCallback2->ThreadAssignedToOSThread(managedThreadId, osThreadId);
3013 HRESULT EEToProfInterfaceImpl::ThreadNameChanged(ThreadID managedThreadId,
3015 __in_ecount_opt(cchName) WCHAR name[])
3032 ASSERT_NO_EE_LOCKS_HELD();
3038 if (reinterpret_cast<Thread *>(managedThreadId)->IsGCSpecial())
3041 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(managedThreadId,
3044 "**PROF: Notifying profiler of thread name change.\n"));
3047 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3048 // whose try/catch blocks aren't visible to the contract system
3049 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3050 return m_pCallback2->ThreadNameChanged(managedThreadId, cchName, name);
3054 //---------------------------------------------------------------------------------------
3055 // EE STARTUP/SHUTDOWN EVENTS
3058 HRESULT EEToProfInterfaceImpl::Shutdown()
3075 ASSERT_NO_EE_LOCKS_HELD();
3081 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3083 "**PROF: Notifying profiler that shutdown is beginning.\n"));
3086 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3087 // whose try/catch blocks aren't visible to the contract system
3088 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3089 return m_pCallback2->Shutdown();
3093 //---------------------------------------------------------------------------------------
3094 // JIT/FUNCTION EVENTS
3097 HRESULT EEToProfInterfaceImpl::FunctionUnloadStarted(FunctionID functionId)
3099 _ASSERTE(!"FunctionUnloadStarted() callback no longer issued");
3103 HRESULT EEToProfInterfaceImpl::JITCompilationFinished(FunctionID functionId,
3105 BOOL fIsSafeToBlock)
3121 // The JIT / MethodDesc code likely hold locks while this callback is made
3127 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3129 "**PROF: JITCompilationFinished 0x%p, hr=0x%08x.\n",
3133 _ASSERTE(functionId);
3136 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3137 // whose try/catch blocks aren't visible to the contract system
3138 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3139 return m_pCallback2->JITCompilationFinished(functionId, hrStatus, fIsSafeToBlock);
3144 HRESULT EEToProfInterfaceImpl::JITCompilationStarted(FunctionID functionId,
3145 BOOL fIsSafeToBlock)
3161 // The JIT / MethodDesc code likely hold locks while this callback is made
3167 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3169 "**PROF: JITCompilationStarted 0x%p.\n",
3172 // Currently JITCompilationStarted is always called with fIsSafeToBlock==TRUE. If this ever changes,
3173 // it's safe to remove this assert, but this should serve as a trigger to change our
3174 // public documentation to state that this callback is no longer called in preemptive mode all the time.
3175 _ASSERTE(fIsSafeToBlock);
3177 _ASSERTE(functionId);
3180 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3181 // whose try/catch blocks aren't visible to the contract system
3182 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3183 return m_pCallback2->JITCompilationStarted(functionId, fIsSafeToBlock);
3187 HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchStarted(
3188 /* [in] */ FunctionID functionId,
3189 /* [out] */ BOOL *pbUseCachedFunction)
3205 // The JIT / MethodDesc code likely hold locks while this callback is made
3211 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3213 "**PROF: JITCachedFunctionSearchStarted 0x%p.\n",
3215 _ASSERTE(functionId);
3216 _ASSERTE(pbUseCachedFunction != NULL);
3219 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3220 // whose try/catch blocks aren't visible to the contract system
3221 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3222 return m_pCallback2->JITCachedFunctionSearchStarted(functionId, pbUseCachedFunction);
3226 HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchFinished(
3227 /* [in] */ FunctionID functionId,
3228 /* [in] */ COR_PRF_JIT_CACHE result)
3244 // The JIT / MethodDesc code likely hold locks while this callback is made
3250 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3252 "**PROF: JITCachedFunctionSearchFinished 0x%p, %s.\n",
3254 (result == COR_PRF_CACHED_FUNCTION_FOUND ?
3255 "Cached function found" :
3256 "Cached function not found")));
3258 _ASSERTE(functionId);
3261 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3262 // whose try/catch blocks aren't visible to the contract system
3263 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3264 return m_pCallback2->JITCachedFunctionSearchFinished(functionId, result);
3269 HRESULT EEToProfInterfaceImpl::JITFunctionPitched(FunctionID functionId)
3271 _ASSERTE(!"JITFunctionPitched() callback no longer issued");
3275 HRESULT EEToProfInterfaceImpl::JITInlining(
3276 /* [in] */ FunctionID callerId,
3277 /* [in] */ FunctionID calleeId,
3278 /* [out] */ BOOL * pfShouldInline)
3294 // The JIT / MethodDesc code likely hold locks while this callback is made
3300 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3302 "**PROF: JITInlining caller: 0x%p, callee: 0x%p.\n",
3310 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3311 // whose try/catch blocks aren't visible to the contract system
3312 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3313 return m_pCallback2->JITInlining(callerId, calleeId, pfShouldInline);
3317 HRESULT EEToProfInterfaceImpl::ReJITCompilationStarted(
3318 /* [in] */ FunctionID functionId,
3319 /* [in] */ ReJITID reJitId,
3320 /* [in] */ BOOL fIsSafeToBlock)
3336 // The JIT / MethodDesc code likely hold locks while this callback is made
3342 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3344 "**PROF: ReJITCompilationStarted 0x%p 0x%p.\n",
3345 functionId, reJitId));
3347 // Should only be called on profilers that support ICorProfilerCallback4
3348 _ASSERTE(m_pCallback4 != NULL);
3350 // Currently ReJITCompilationStarted is always called with fIsSafeToBlock==TRUE. If this ever changes,
3351 // it's safe to remove this assert, but this should serve as a trigger to change our
3352 // public documentation to state that this callback is no longer called in preemptive mode all the time.
3353 _ASSERTE(fIsSafeToBlock);
3355 _ASSERTE(functionId);
3359 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3360 // whose try/catch blocks aren't visible to the contract system
3361 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3362 return m_pCallback4->ReJITCompilationStarted(functionId, reJitId, fIsSafeToBlock);
3366 HRESULT EEToProfInterfaceImpl::GetReJITParameters(
3367 /* [in] */ ModuleID moduleId,
3368 /* [in] */ mdMethodDef methodId,
3369 /* [in] */ ICorProfilerFunctionControl *
3386 // The ReJIT code holds a lock while this callback is made
3392 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3394 "**PROF: GetReJITParameters 0x%p 0x%p.\n",
3395 moduleId, methodId));
3397 // Should only be called on profilers that support ICorProfilerCallback4
3398 _ASSERTE(m_pCallback4 != NULL);
3403 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3404 // whose try/catch blocks aren't visible to the contract system
3405 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3406 return m_pCallback4->GetReJITParameters(moduleId, methodId, pFunctionControl);
3410 HRESULT EEToProfInterfaceImpl::ReJITCompilationFinished(
3411 /* [in] */ FunctionID functionId,
3412 /* [in] */ ReJITID reJitId,
3413 /* [in] */ HRESULT hrStatus,
3414 /* [in] */ BOOL fIsSafeToBlock)
3430 // ReJit holds a lock as well as possibly others...
3436 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3438 "**PROF: ReJITCompilationFinished 0x%p 0x%p hr=0x%x.\n",
3439 functionId, reJitId, hrStatus));
3441 // Should only be called on profilers that support ICorProfilerCallback4
3442 _ASSERTE(m_pCallback4 != NULL);
3444 _ASSERTE(functionId);
3448 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3449 // whose try/catch blocks aren't visible to the contract system
3450 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3451 return m_pCallback4->ReJITCompilationFinished(functionId, reJitId, hrStatus, fIsSafeToBlock);
3456 HRESULT EEToProfInterfaceImpl::ReJITError(
3457 /* [in] */ ModuleID moduleId,
3458 /* [in] */ mdMethodDef methodId,
3459 /* [in] */ FunctionID functionId,
3460 /* [in] */ HRESULT hrStatus)
3480 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3482 "**PROF: ReJITError 0x%p 0x%x 0x%p 0x%x.\n",
3483 moduleId, methodId, functionId, hrStatus));
3485 // Should only be called on profilers that support ICorProfilerCallback4
3486 _ASSERTE(m_pCallback4 != NULL);
3489 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3490 // whose try/catch blocks aren't visible to the contract system
3491 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3492 return m_pCallback4->ReJITError(moduleId, methodId, functionId, hrStatus);
3496 //---------------------------------------------------------------------------------------
3500 HRESULT EEToProfInterfaceImpl::ModuleLoadStarted(ModuleID moduleId)
3510 // This has historically not run in preemptive, and is called from cooperative-mode
3511 // functions. However, since we're triggers, it might actually be safe to consider
3512 // letting this run in preemptive mode.
3519 ASSERT_NO_EE_LOCKS_HELD();
3525 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3527 "**PROF: ModuleLoadStarted 0x%p.\n",
3530 _ASSERTE(moduleId != 0);
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_pCallback2->ModuleLoadStarted(moduleId);
3541 HRESULT EEToProfInterfaceImpl::ModuleLoadFinished(
3560 ASSERT_NO_EE_LOCKS_HELD();
3566 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3568 "**PROF: ModuleLoadFinished 0x%p.\n",
3571 _ASSERTE(moduleId != 0);
3574 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3575 // whose try/catch blocks aren't visible to the contract system
3576 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3577 return m_pCallback2->ModuleLoadFinished(moduleId, hrStatus);
3583 HRESULT EEToProfInterfaceImpl::ModuleUnloadStarted(
3601 ASSERT_NO_EE_LOCKS_HELD();
3607 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3609 "**PROF: ModuleUnloadStarted 0x%p.\n",
3612 _ASSERTE(moduleId != 0);
3615 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3616 // whose try/catch blocks aren't visible to the contract system
3617 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3618 return m_pCallback2->ModuleUnloadStarted(moduleId);
3623 HRESULT EEToProfInterfaceImpl::ModuleUnloadFinished(
3642 ASSERT_NO_EE_LOCKS_HELD();
3648 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3650 "**PROF: ModuleUnloadFinished 0x%p.\n",
3652 _ASSERTE(moduleId != 0);
3654 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3655 // whose try/catch blocks aren't visible to the contract system
3656 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3657 return m_pCallback2->ModuleUnloadFinished(moduleId, hrStatus);
3662 HRESULT EEToProfInterfaceImpl::ModuleAttachedToAssembly(
3664 AssemblyID AssemblyId)
3681 ASSERT_NO_EE_LOCKS_HELD();
3687 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3689 "**PROF: ModuleAttachedToAssembly 0x%p, 0x%p.\n",
3693 _ASSERTE(moduleId != 0);
3696 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3697 // whose try/catch blocks aren't visible to the contract system
3698 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3699 return m_pCallback2->ModuleAttachedToAssembly(moduleId, AssemblyId);
3703 HRESULT EEToProfInterfaceImpl::ModuleInMemorySymbolsUpdated(ModuleID moduleId)
3723 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3725 "**PROF: ModuleInMemorySymbolsUpdated. moduleId: 0x%p.\n",
3730 _ASSERTE(IsCallback7Supported());
3733 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3734 // whose try/catch blocks aren't visible to the contract system
3735 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3736 hr = m_pCallback7->ModuleInMemorySymbolsUpdated(moduleId);
3742 //---------------------------------------------------------------------------------------
3746 HRESULT EEToProfInterfaceImpl::ClassLoadStarted(
3763 // UnresolvedClassLock typically held during this callback
3769 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3771 "**PROF: ClassLoadStarted 0x%p.\n",
3777 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3778 // whose try/catch blocks aren't visible to the contract system
3779 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3780 return m_pCallback2->ClassLoadStarted(classId);
3785 HRESULT EEToProfInterfaceImpl::ClassLoadFinished(
3803 // UnresolvedClassLock typically held during this callback
3809 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3811 "**PROF: ClassLoadFinished 0x%p, 0x%08x.\n",
3818 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3819 // whose try/catch blocks aren't visible to the contract system
3820 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3821 return m_pCallback2->ClassLoadFinished(classId, hrStatus);
3826 HRESULT EEToProfInterfaceImpl::ClassUnloadStarted(
3843 // Although not typical, it's possible for UnresolvedClassLock to be held
3844 // during this callback. This can occur if, during the class load, an
3845 // exception is thrown, and EEClass::Destruct is called from the catch clause
3846 // inside ClassLoader::CreateTypeHandleForTypeDefThrowing.
3852 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3854 "**PROF: ClassUnloadStarted 0x%p.\n",
3860 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3861 // whose try/catch blocks aren't visible to the contract system
3862 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3863 return m_pCallback2->ClassUnloadStarted(classId);
3868 HRESULT EEToProfInterfaceImpl::ClassUnloadFinished(
3886 // Locks can be held when this is called. See comment in ClassUnloadStarted
3892 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3894 "**PROF: ClassUnloadFinished 0x%p, 0x%08x.\n",
3901 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3902 // whose try/catch blocks aren't visible to the contract system
3903 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3904 return m_pCallback2->ClassUnloadFinished(classId, hrStatus);
3908 //---------------------------------------------------------------------------------------
3912 HRESULT EEToProfInterfaceImpl::AppDomainCreationStarted(
3913 AppDomainID appDomainId)
3930 ASSERT_NO_EE_LOCKS_HELD();
3936 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3938 "**PROF: AppDomainCreationStarted 0x%p.\n",
3941 _ASSERTE(appDomainId != 0);
3944 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3945 // whose try/catch blocks aren't visible to the contract system
3946 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3947 return m_pCallback2->AppDomainCreationStarted(appDomainId);
3952 HRESULT EEToProfInterfaceImpl::AppDomainCreationFinished(
3953 AppDomainID appDomainId,
3971 ASSERT_NO_EE_LOCKS_HELD();
3977 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3979 "**PROF: AppDomainCreationFinished 0x%p, 0x%08x.\n",
3983 _ASSERTE(appDomainId != 0);
3986 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3987 // whose try/catch blocks aren't visible to the contract system
3988 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3989 return m_pCallback2->AppDomainCreationFinished(appDomainId, hrStatus);
3993 HRESULT EEToProfInterfaceImpl::AppDomainShutdownStarted(
3994 AppDomainID appDomainId)
4011 ASSERT_NO_EE_LOCKS_HELD();
4017 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4019 "**PROF: AppDomainShutdownStarted 0x%p.\n",
4022 _ASSERTE(appDomainId != 0);
4025 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4026 // whose try/catch blocks aren't visible to the contract system
4027 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4028 return m_pCallback2->AppDomainShutdownStarted(appDomainId);
4032 HRESULT EEToProfInterfaceImpl::AppDomainShutdownFinished(
4033 AppDomainID appDomainId,
4051 ASSERT_NO_EE_LOCKS_HELD();
4057 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4059 "**PROF: AppDomainShutdownFinished 0x%p, 0x%08x.\n",
4063 _ASSERTE(appDomainId != 0);
4066 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4067 // whose try/catch blocks aren't visible to the contract system
4068 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4069 return m_pCallback2->AppDomainShutdownFinished(appDomainId, hrStatus);
4073 //---------------------------------------------------------------------------------------
4077 HRESULT EEToProfInterfaceImpl::AssemblyLoadStarted(
4078 AssemblyID assemblyId)
4088 // This has historically not run in preemptive, and is called from cooperative-mode
4089 // functions. However, since we're triggers, it might actually be safe to consider
4090 // letting this run in preemptive mode.
4097 ASSERT_NO_EE_LOCKS_HELD();
4103 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4105 "**PROF: AssemblyLoadStarted 0x%p.\n",
4108 _ASSERTE(assemblyId != 0);
4111 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4112 // whose try/catch blocks aren't visible to the contract system
4113 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4114 return m_pCallback2->AssemblyLoadStarted(assemblyId);
4118 HRESULT EEToProfInterfaceImpl::AssemblyLoadFinished(
4119 AssemblyID assemblyId,
4130 // This has historically not run in preemptive, and is called from cooperative-mode
4131 // functions. However, since we're triggers, it might actually be safe to consider
4132 // letting this run in preemptive mode.
4139 ASSERT_NO_EE_LOCKS_HELD();
4145 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4147 "**PROF: AssemblyLoadFinished 0x%p, 0x%08x.\n",
4151 _ASSERTE(assemblyId != 0);
4154 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4155 // whose try/catch blocks aren't visible to the contract system
4156 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4157 return m_pCallback2->AssemblyLoadFinished(assemblyId, hrStatus);
4161 HRESULT EEToProfInterfaceImpl::AssemblyUnloadStarted(
4162 AssemblyID assemblyId)
4179 ASSERT_NO_EE_LOCKS_HELD();
4185 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4187 "**PROF: AssemblyUnloadStarted 0x%p.\n",
4190 _ASSERTE(assemblyId != 0);
4193 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4194 // whose try/catch blocks aren't visible to the contract system
4195 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4196 return m_pCallback2->AssemblyUnloadStarted(assemblyId);
4200 HRESULT EEToProfInterfaceImpl::AssemblyUnloadFinished(
4201 AssemblyID assemblyId,
4219 ASSERT_NO_EE_LOCKS_HELD();
4225 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4227 "**PROF: AssemblyUnloadFinished 0x%p, 0x%08x.\n",
4231 _ASSERTE(assemblyId != 0);
4234 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4235 // whose try/catch blocks aren't visible to the contract system
4236 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4237 return m_pCallback2->AssemblyUnloadFinished(assemblyId, hrStatus);
4241 //---------------------------------------------------------------------------------------
4242 // TRANSITION EVENTS
4245 HRESULT EEToProfInterfaceImpl::UnmanagedToManagedTransition(
4246 FunctionID functionId,
4247 COR_PRF_TRANSITION_REASON reason)
4264 ASSERT_NO_EE_LOCKS_HELD();
4270 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4272 "**PROF: UnmanagedToManagedTransition 0x%p.\n",
4275 _ASSERTE(reason == COR_PRF_TRANSITION_CALL || reason == COR_PRF_TRANSITION_RETURN);
4278 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4279 // whose try/catch blocks aren't visible to the contract system
4280 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4281 return m_pCallback2->UnmanagedToManagedTransition(functionId, reason);
4285 HRESULT EEToProfInterfaceImpl::ManagedToUnmanagedTransition(
4286 FunctionID functionId,
4287 COR_PRF_TRANSITION_REASON reason)
4304 ASSERT_NO_EE_LOCKS_HELD();
4310 _ASSERTE(reason == COR_PRF_TRANSITION_CALL || reason == COR_PRF_TRANSITION_RETURN);
4312 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4314 "**PROF: ManagedToUnmanagedTransition 0x%p.\n",
4318 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4319 // whose try/catch blocks aren't visible to the contract system
4320 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4321 return m_pCallback2->ManagedToUnmanagedTransition(functionId, reason);
4325 //---------------------------------------------------------------------------------------
4329 HRESULT EEToProfInterfaceImpl::ExceptionThrown(
4330 ObjectID thrownObjectId)
4340 // Preemptive mode would be bad, dude. There's an objectId in the param list!
4347 ASSERT_NO_EE_LOCKS_HELD();
4353 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4355 "**PROF: ExceptionThrown. ObjectID: 0x%p. ThreadID: 0x%p\n",
4360 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4361 // whose try/catch blocks aren't visible to the contract system
4362 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4363 return m_pCallback2->ExceptionThrown(thrownObjectId);
4367 HRESULT EEToProfInterfaceImpl::ExceptionSearchFunctionEnter(
4368 FunctionID functionId)
4385 ASSERT_NO_EE_LOCKS_HELD();
4391 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4393 "**PROF: ExceptionSearchFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4398 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4399 // whose try/catch blocks aren't visible to the contract system
4400 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4401 return m_pCallback2->ExceptionSearchFunctionEnter(functionId);
4405 HRESULT EEToProfInterfaceImpl::ExceptionSearchFunctionLeave()
4422 ASSERT_NO_EE_LOCKS_HELD();
4428 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4430 "**PROF: ExceptionSearchFunctionLeave. ThreadID: 0x%p\n",
4434 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4435 // whose try/catch blocks aren't visible to the contract system
4436 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4437 return m_pCallback2->ExceptionSearchFunctionLeave();
4441 HRESULT EEToProfInterfaceImpl::ExceptionSearchFilterEnter(FunctionID functionId)
4458 ASSERT_NO_EE_LOCKS_HELD();
4464 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4466 "**PROF: ExceptionSearchFilterEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4471 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4472 // whose try/catch blocks aren't visible to the contract system
4473 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4474 return m_pCallback2->ExceptionSearchFilterEnter(functionId);
4478 HRESULT EEToProfInterfaceImpl::ExceptionSearchFilterLeave()
4495 ASSERT_NO_EE_LOCKS_HELD();
4501 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4503 "**PROF: ExceptionFilterLeave. ThreadID: 0x%p\n",
4507 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4508 // whose try/catch blocks aren't visible to the contract system
4509 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4510 return m_pCallback2->ExceptionSearchFilterLeave();
4514 HRESULT EEToProfInterfaceImpl::ExceptionSearchCatcherFound(FunctionID functionId)
4531 ASSERT_NO_EE_LOCKS_HELD();
4537 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4539 "**PROF: ExceptionSearchCatcherFound. ThreadID: 0x%p\n",
4543 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4544 // whose try/catch blocks aren't visible to the contract system
4545 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4546 return m_pCallback2->ExceptionSearchCatcherFound(functionId);
4550 HRESULT EEToProfInterfaceImpl::ExceptionOSHandlerEnter(FunctionID functionId)
4552 _ASSERTE(!"ExceptionOSHandlerEnter() callback no longer issued");
4556 HRESULT EEToProfInterfaceImpl::ExceptionOSHandlerLeave(FunctionID functionId)
4558 _ASSERTE(!"ExceptionOSHandlerLeave() callback no longer issued");
4562 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFunctionEnter(FunctionID functionId)
4569 // Called by COMPlusUnwindCallback, which is notrigger
4572 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4573 // Thus, the profiler cannot block on this call.
4580 ASSERT_NO_EE_LOCKS_HELD();
4586 CLR_TO_PROFILER_ENTRYPOINT_EX(
4590 "**PROF: ExceptionUnwindFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4595 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4596 // whose try/catch blocks aren't visible to the contract system
4597 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4598 return m_pCallback2->ExceptionUnwindFunctionEnter(functionId);
4602 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFunctionLeave()
4609 // Called by COMPlusUnwindCallback, which is notrigger
4612 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4613 // Thus, the profiler cannot block on this call.
4620 ASSERT_NO_EE_LOCKS_HELD();
4626 CLR_TO_PROFILER_ENTRYPOINT_EX(
4630 "**PROF: ExceptionUnwindFunctionLeave. ThreadID: 0x%p\n",
4634 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4635 // whose try/catch blocks aren't visible to the contract system
4636 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4637 return m_pCallback2->ExceptionUnwindFunctionLeave();
4641 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFinallyEnter(FunctionID functionId)
4648 // Called by COMPlusUnwindCallback, which is notrigger
4651 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4652 // Thus, the profiler cannot block on this call.
4659 ASSERT_NO_EE_LOCKS_HELD();
4665 CLR_TO_PROFILER_ENTRYPOINT_EX(
4669 "**PROF: ExceptionUnwindFinallyEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4674 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4675 // whose try/catch blocks aren't visible to the contract system
4676 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4677 return m_pCallback2->ExceptionUnwindFinallyEnter(functionId);
4681 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFinallyLeave()
4688 // Called by COMPlusUnwindCallback, which is notrigger
4691 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4692 // Thus, the profiler cannot block on this call.
4699 ASSERT_NO_EE_LOCKS_HELD();
4705 CLR_TO_PROFILER_ENTRYPOINT_EX(
4709 "**PROF: ExceptionUnwindFinallyLeave. ThreadID: 0x%p\n",
4713 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4714 // whose try/catch blocks aren't visible to the contract system
4715 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4716 return m_pCallback2->ExceptionUnwindFinallyLeave();
4720 HRESULT EEToProfInterfaceImpl::ExceptionCatcherEnter(FunctionID functionId, ObjectID objectId)
4727 // Called by COMPlusUnwindCallback, which is notrigger
4730 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4731 // Thus, the profiler cannot block on this call.
4738 ASSERT_NO_EE_LOCKS_HELD();
4744 CLR_TO_PROFILER_ENTRYPOINT_EX(
4747 LL_INFO1000, "**PROF: ExceptionCatcherEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4752 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4753 // whose try/catch blocks aren't visible to the contract system
4754 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4755 return m_pCallback2->ExceptionCatcherEnter(functionId, objectId);
4759 HRESULT EEToProfInterfaceImpl::ExceptionCatcherLeave()
4769 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4770 // Thus, the profiler cannot block on this call.
4777 ASSERT_NO_EE_LOCKS_HELD();
4783 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4785 "**PROF: ExceptionCatcherLeave. ThreadID: 0x%p\n",
4790 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4791 // whose try/catch blocks aren't visible to the contract system
4792 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4793 return m_pCallback2->ExceptionCatcherLeave();
4798 //---------------------------------------------------------------------------------------
4799 // COM Callable Wrapper EVENTS
4802 HRESULT EEToProfInterfaceImpl::COMClassicVTableCreated(
4803 /* [in] */ ClassID classId,
4804 /* [in] */ REFGUID implementedIID,
4805 /* [in] */ void *pVTable,
4806 /* [in] */ ULONG cSlots)
4823 ASSERT_NO_EE_LOCKS_HELD();
4829 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4831 "**PROF: COMClassicWrapperCreated %#x %#08x... %#x %d.\n",
4833 implementedIID.Data1,
4838 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4839 // whose try/catch blocks aren't visible to the contract system
4840 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4841 return m_pCallback2->COMClassicVTableCreated(classId, implementedIID, pVTable, cSlots);
4845 HRESULT EEToProfInterfaceImpl::COMClassicVTableDestroyed(
4846 /* [in] */ ClassID classId,
4847 /* [in] */ REFGUID implementedIID,
4848 /* [in] */ void *pVTable)
4865 ASSERT_NO_EE_LOCKS_HELD();
4871 // NOTE: There is no problem with this code, and it is ready and willing
4872 // to be called. However, this callback is intentionally not being
4873 // issued currently. See comment in ComMethodTable::Cleanup() for more
4876 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4878 "**PROF: COMClassicWrapperDestroyed %#x %#08x... %#x.\n",
4880 implementedIID.Data1,
4884 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4885 // whose try/catch blocks aren't visible to the contract system
4886 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4887 return m_pCallback2->COMClassicVTableDestroyed(classId, implementedIID, pVTable);
4892 //---------------------------------------------------------------------------------------
4893 // GC THREADING EVENTS
4896 HRESULT EEToProfInterfaceImpl::RuntimeSuspendStarted(
4897 COR_PRF_SUSPEND_REASON suspendReason)
4904 // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
4905 // not to allow a GC to occur while we're suspending / resuming the runtime, this is
4906 // the thread trying to do a GC. So if the profiler tries to trigger another GC from
4907 // this thread at this time, we might see potential recursion or deadlock.
4915 // Thread store lock is typically held during this callback
4921 CLR_TO_PROFILER_ENTRYPOINT_EX(
4925 "**PROF: RuntimeSuspendStarted. 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->RuntimeSuspendStarted(suspendReason);
4936 HRESULT EEToProfInterfaceImpl::RuntimeSuspendFinished()
4943 // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
4944 // not to allow a GC to occur while we're suspending / resuming the runtime, this is
4945 // the thread trying to do a GC. So if the profiler tries to trigger another GC from
4946 // this thread at this time, we might see potential recursion or deadlock.
4954 // Thread store lock is typically held during this callback
4960 CLR_TO_PROFILER_ENTRYPOINT_EX(
4964 "**PROF: RuntimeSuspendFinished. ThreadID 0x%p.\n",
4969 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4970 // whose try/catch blocks aren't visible to the contract system
4971 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4972 return m_pCallback2->RuntimeSuspendFinished();
4976 HRESULT EEToProfInterfaceImpl::RuntimeSuspendAborted()
4983 // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
4984 // not to allow a GC to occur while we're suspending / resuming the runtime, this is
4985 // the thread trying to do a GC. So if the profiler tries to trigger another GC from
4986 // this thread at this time, we might see potential recursion or deadlock.
4989 // NOTE: I have no empirical data for gc mode: none of the self-host BVTs call this
4990 // So for now, assume this is callable in any mode.
4991 // This has historically not caused a mode change to preemptive, and is called from
4992 // cooperative-mode functions. Also, switching to preemptive while we're suspending
4993 // the runtime just seems like a bad idea.
4999 // Thread store lock is typically held during this callback
5005 CLR_TO_PROFILER_ENTRYPOINT_EX(
5009 "**PROF: RuntimeSuspendAborted. ThreadID 0x%p.\n",
5013 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5014 // whose try/catch blocks aren't visible to the contract system
5015 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5016 return m_pCallback2->RuntimeSuspendAborted();
5020 HRESULT EEToProfInterfaceImpl::RuntimeResumeStarted()
5030 // This has historically not caused a mode change to preemptive, and is called from
5031 // cooperative-mode functions. Also, switching to preemptive while we're resuming
5032 // the runtime just seems like a bad idea.
5038 // Thread store lock is typically held during this callback
5044 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5046 "**PROF: RuntimeResumeStarted. ThreadID 0x%p.\n",
5050 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5051 // whose try/catch blocks aren't visible to the contract system
5052 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5053 return m_pCallback2->RuntimeResumeStarted();
5057 HRESULT EEToProfInterfaceImpl::RuntimeResumeFinished()
5073 // Thread store lock is typically held during this callback
5079 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5081 "**PROF: RuntimeResumeFinished. ThreadID 0x%p.\n",
5085 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5086 // whose try/catch blocks aren't visible to the contract system
5087 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5088 return m_pCallback2->RuntimeResumeFinished();
5092 HRESULT EEToProfInterfaceImpl::RuntimeThreadSuspended(ThreadID suspendedThreadId)
5099 // Called by Thread::SuspendThread, which is notrigger.
5102 // Although I've verified we're called from both coop and preemp, we need to
5103 // avoid switching to preemptive to satisfy our notrigger paths.
5109 // Thread store lock is typically held during this callback
5115 if (reinterpret_cast<Thread *>(suspendedThreadId)->IsGCSpecial())
5118 // NOTE: We cannot use the standard CLR_TO_PROFILER_ENTRYPOINT macro here because
5119 // we might be called at a time when profiler callbacks have been disallowed for
5120 // this thread. So we cannot simply ASSERT that callbacks are allowed (as this macro
5121 // does). Instead, we must explicitly check for this condition and return gracefully
5122 // if callbacks are disallowed. So the macro is unwrapped here manually
5124 CHECK_PROFILER_STATUS(kEE2PNone);
5126 LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadSuspended. ThreadID 0x%p.\n",
5127 suspendedThreadId));
5129 // NOTE: We're notrigger, so we cannot switch to preemptive mode.
5131 // We may have already indicated to the profiler that this thread has died, but
5132 // the runtime may continue to suspend this thread during the process of destroying
5133 // the thread, so we do not want to indicate to the profiler these suspensions.
5134 if (!ProfilerCallbacksAllowedForThread((Thread *) suspendedThreadId))
5139 // Remaining essentials from our entrypoint macros with kEE2PNoTrigger flag
5140 SetCallbackStateFlagsHolder csf(COR_PRF_CALLBACKSTATE_INCALLBACK);
5141 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
5142 _ASSERTE(m_pCallback2 != NULL);
5145 // SCOPE: ForbidSuspendThreadHolder
5147 // The ForbidSuspendThreadHolder prevents deadlocks under the following scenario:
5148 // 1) Thread A blocks waiting for the current GC to complete (this can happen if A is trying to
5149 // switch to cooperative during a GC).
5150 // 2) This causes us to send a RuntimeThreadSuspended callback to the profiler. (Although
5151 // A isn't technically being "suspended", this blocking is considered suspension as far as the
5152 // profapi is concerned.)
5153 // 3) Profiler, in turn, may take one of its own private locks to synchronize this callback with
5154 // the profiler's attempt to hijack thread A. Specifically, the profiler knows it's not allowed
5155 // to hijack A if A is getting suspended by the runtime, because this suspension might be due to
5156 // the GC trying to hijack A. And if the GC tries to hijack A at the same time as the profiler
5157 // hijacking A and the profiler wins, then GC asserts because A is no longer at the IP that
5158 // the GC thought (VsWhidbey 428477, 429741)
5159 // 4) Meanwhile, thread B (GC thread) is suspending the runtime, and calls Thread::SuspendThread()
5160 // on A. This is the bad thing we're trying to avoid, because when this happens, we call into
5161 // the profiler AGAIN with RuntimeThreadSuspended for thread A, and the profiler again
5162 // tries to grab the lock it acquired in step 3). Yes, at this point we now have two simultaneous
5163 // calls into the profiler's RuntimeThreadSuspended() callback. One saying A is suspending A
5164 // (3 above), and one saying B is suspending A (this step (4)). The problem is that A is now officially
5165 // hard suspended, OS-style, so the lock acquired on 3) ain't never getting released until
5166 // A is resumed. But A won't be resumed until B resumes it. And B won't resume A until
5167 // the profiler returns from its RuntimeThreadSuspended callback. And the profiler
5168 // can't return from its RuntimeThreadSuspended callback until it acquires this lock it tried to
5169 // acquire in 4). And it can't acquire this lock until A is finally resumed so that the acquire
5170 // from 3) is released. Have we gone in a circle yet?
5171 // In order to avoid 4) we inc the ForbidSuspendThread count during 3) to prevent the hard suspension
5172 // (4) from occurring until 3) is completely done. It's sufficient to determine we're in 3) by noting
5173 // whether the callback is reporting that a thread is "suspending itself" (i.e., suspendedThreadId == threadId)
5175 ForbidSuspendThreadHolder forbidSuspendThread((Thread *) suspendedThreadId == GetThread());
5178 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5179 // whose try/catch blocks aren't visible to the contract system
5180 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5181 return m_pCallback2->RuntimeThreadSuspended(suspendedThreadId);
5186 HRESULT EEToProfInterfaceImpl::RuntimeThreadResumed(ThreadID resumedThreadId)
5193 // This gets called in response to another profapi function:
5194 // ICorProfilerInfo2::DoStackSnapshot! And that dude is called asynchronously and
5195 // must therefore never cause a GC.
5196 // Other reasons for notrigger: also called by notrigger dudes Thread::SysStartSuspendForDebug,
5197 // CheckSuspended, Thread::IsRunningIn, Thread::IsExecutingWithinCer, Thread::IsExecutingWithinCer,
5201 // Although we cannot trigger, verified empirically that this called coop & preemp
5207 // Thread store lock is typically held during this callback
5213 if (reinterpret_cast<Thread *>(resumedThreadId)->IsGCSpecial())
5216 // NOTE: We cannot use the standard CLR_TO_PROFILER_ENTRYPOINT macro here because
5217 // we might be called at a time when profiler callbacks have been disallowed for
5218 // this thread. So we cannot simply ASSERT that callbacks are allowed (as this macro
5219 // does). Instead, we must explicitly check for this condition and return gracefully
5220 // if callbacks are disallowed. So the macro is unwrapped here manually
5222 CHECK_PROFILER_STATUS(kEE2PNone);
5224 LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadResumed. ThreadID 0x%p.\n", resumedThreadId));
5226 // NOTE: We're notrigger, so we cannot switch to preemptive mode.
5228 // We may have already indicated to the profiler that this thread has died, but
5229 // the runtime may resume this thread during the process of destroying
5230 // the thread, so we do not want to indicate to the profiler these resumes.
5231 if (!ProfilerCallbacksAllowedForThread((Thread *) resumedThreadId))
5236 // Remaining essentials from our entrypoint macros with kEE2PNoTrigger flag
5237 SetCallbackStateFlagsHolder csf(COR_PRF_CALLBACKSTATE_INCALLBACK);
5238 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
5239 _ASSERTE(m_pCallback2 != NULL);
5242 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5243 // whose try/catch blocks aren't visible to the contract system
5244 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5245 return m_pCallback2->RuntimeThreadResumed(resumedThreadId);
5249 //---------------------------------------------------------------------------------------
5253 HRESULT EEToProfInterfaceImpl::RemotingClientInvocationStarted()
5270 ASSERT_NO_EE_LOCKS_HELD();
5276 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5278 "**PROF: RemotingClientInvocationStarted. ThreadID: 0x%p\n",
5282 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5283 // whose try/catch blocks aren't visible to the contract system
5284 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5285 return m_pCallback2->RemotingClientInvocationStarted();
5289 HRESULT EEToProfInterfaceImpl::RemotingClientSendingMessage(GUID *pCookie, BOOL fIsAsync)
5306 ASSERT_NO_EE_LOCKS_HELD();
5312 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5314 "**PROF: RemotingClientSendingMessage. ThreadID: 0x%p\n",
5318 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5319 // whose try/catch blocks aren't visible to the contract system
5320 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5321 return m_pCallback2->RemotingClientSendingMessage(pCookie, fIsAsync);
5325 HRESULT EEToProfInterfaceImpl::RemotingClientReceivingReply(GUID * pCookie, BOOL fIsAsync)
5342 ASSERT_NO_EE_LOCKS_HELD();
5348 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5350 "**PROF: RemotingClientReceivingReply. ThreadID: 0x%p\n",
5354 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5355 // whose try/catch blocks aren't visible to the contract system
5356 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5357 return m_pCallback2->RemotingClientReceivingReply(pCookie, fIsAsync);
5361 HRESULT EEToProfInterfaceImpl::RemotingClientInvocationFinished()
5378 ASSERT_NO_EE_LOCKS_HELD();
5384 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5386 "**PROF: RemotingClientInvocationFinished. ThreadID: 0x%p\n",
5390 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5391 // whose try/catch blocks aren't visible to the contract system
5392 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5393 return m_pCallback2->RemotingClientInvocationFinished();
5397 HRESULT EEToProfInterfaceImpl::RemotingServerReceivingMessage(GUID *pCookie, BOOL fIsAsync)
5414 ASSERT_NO_EE_LOCKS_HELD();
5420 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5422 "**PROF: RemotingServerReceivingMessage. ThreadID: 0x%p\n",
5426 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5427 // whose try/catch blocks aren't visible to the contract system
5428 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5429 return m_pCallback2->RemotingServerReceivingMessage(pCookie, fIsAsync);
5433 HRESULT EEToProfInterfaceImpl::RemotingServerInvocationStarted()
5450 ASSERT_NO_EE_LOCKS_HELD();
5456 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5458 "**PROF: RemotingServerInvocationStarted. ThreadID: 0x%p\n",
5462 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5463 // whose try/catch blocks aren't visible to the contract system
5464 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5465 return m_pCallback2->RemotingServerInvocationStarted();
5469 HRESULT EEToProfInterfaceImpl::RemotingServerInvocationReturned()
5486 ASSERT_NO_EE_LOCKS_HELD();
5492 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5494 "**PROF: RemotingServerInvocationReturned. ThreadID: 0x%p\n",
5498 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5499 // whose try/catch blocks aren't visible to the contract system
5500 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5501 return m_pCallback2->RemotingServerInvocationReturned();
5505 HRESULT EEToProfInterfaceImpl::RemotingServerSendingReply(GUID *pCookie, BOOL fIsAsync)
5522 ASSERT_NO_EE_LOCKS_HELD();
5528 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5530 "**PROF: RemotingServerSendingReply. ThreadID: 0x%p\n",
5534 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5535 // whose try/catch blocks aren't visible to the contract system
5536 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5537 return m_pCallback2->RemotingServerSendingReply(pCookie, fIsAsync);
5541 //---------------------------------------------------------------------------------------
5545 HRESULT EEToProfInterfaceImpl::ObjectAllocated(
5546 /* [in] */ ObjectID objectId,
5547 /* [in] */ ClassID classId)
5557 // Preemptive mode would be bad, dude. There's an objectId in the param list!
5563 // CrstAppDomainHandleTable can be held while this is called
5569 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5571 "**PROF: ObjectAllocated. ObjectID: 0x%p. ClassID: 0x%p\n",
5576 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5577 // whose try/catch blocks aren't visible to the contract system
5578 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5579 return m_pCallback2->ObjectAllocated(objectId, classId);
5584 HRESULT EEToProfInterfaceImpl::MovedReferences(GCReferencesData *pData)
5591 // This is called by the thread doing a GC WHILE it does the GC
5594 // This is called by the thread doing a GC WHILE it does the GC
5595 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5600 // Thread store lock normally held during this callback
5606 CLR_TO_PROFILER_ENTRYPOINT_EX(
5610 "**PROF: MovedReferences.\n"));
5612 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5614 if (pData->curIdx == 0)
5621 if (pData->compactingCount != 0)
5623 _ASSERTE(pData->curIdx == pData->compactingCount);
5625 if (m_pCallback4 != NULL)
5627 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5628 // whose try/catch blocks aren't visible to the contract system
5629 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5630 hr = m_pCallback4->MovedReferences2((ULONG)pData->curIdx,
5631 (ObjectID *)pData->arrpbMemBlockStartOld,
5632 (ObjectID *)pData->arrpbMemBlockStartNew,
5633 (SIZE_T *)pData->arrMemBlockSize);
5639 // Recompute sizes as ULONGs for legacy callback
5640 for (ULONG i = 0; i < pData->curIdx; i++)
5641 pData->arrULONG[i] = (pData->arrMemBlockSize[i] > ULONG_MAX) ? ULONG_MAX : (ULONG)pData->arrMemBlockSize[i];
5645 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5646 // whose try/catch blocks aren't visible to the contract system
5647 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5648 hr = m_pCallback2->MovedReferences((ULONG)pData->curIdx,
5649 (ObjectID *)pData->arrpbMemBlockStartOld,
5650 (ObjectID *)pData->arrpbMemBlockStartNew,
5656 if (m_pCallback4 != NULL)
5658 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5659 // whose try/catch blocks aren't visible to the contract system
5660 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5661 hr = m_pCallback4->SurvivingReferences2((ULONG)pData->curIdx,
5662 (ObjectID *)pData->arrpbMemBlockStartOld,
5663 (SIZE_T *)pData->arrMemBlockSize);
5669 // Recompute sizes as ULONGs for legacy callback
5670 for (ULONG i = 0; i < pData->curIdx; i++)
5671 pData->arrULONG[i] = (pData->arrMemBlockSize[i] > ULONG_MAX) ? ULONG_MAX : (ULONG)pData->arrMemBlockSize[i];
5675 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5676 // whose try/catch blocks aren't visible to the contract system
5677 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5678 hr = m_pCallback2->SurvivingReferences((ULONG)pData->curIdx,
5679 (ObjectID *)pData->arrpbMemBlockStartOld,
5687 HRESULT EEToProfInterfaceImpl::NotifyAllocByClass(AllocByClassData *pData)
5694 // This is called by the thread doing a GC WHILE it does the GC
5697 // This is called by the thread doing a GC WHILE it does the GC
5698 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5703 // Thread store lock normally held during this callback
5709 CLR_TO_PROFILER_ENTRYPOINT_EX(
5713 "**PROF: ObjectsAllocatedByClass.\n"));
5715 _ASSERTE(pData != NULL);
5716 _ASSERTE(pData->iHash > 0);
5718 // If the arrays are not long enough, get rid of them.
5719 if (pData->cLength != 0 && pData->iHash > pData->cLength)
5721 _ASSERTE(pData->arrClsId != NULL && pData->arrcObjects != NULL);
5722 delete [] pData->arrClsId;
5723 delete [] pData->arrcObjects;
5727 // If there are no arrays, must allocate them.
5728 if (pData->cLength == 0)
5730 pData->arrClsId = new (nothrow) ClassID[pData->iHash];
5731 if (pData->arrClsId == NULL)
5733 return E_OUTOFMEMORY;
5736 pData->arrcObjects = new (nothrow) ULONG[pData->iHash];
5737 if (pData->arrcObjects == NULL)
5739 delete [] pData->arrClsId;
5740 pData->arrClsId= NULL;
5742 return E_OUTOFMEMORY;
5745 // Indicate that the memory was successfully allocated
5746 pData->cLength = pData->iHash;
5749 // Now copy all the data
5751 CLASSHASHENTRY * pCur = (CLASSHASHENTRY *) pData->pHashTable->FindFirstEntry(&hFind);
5752 size_t iCur = 0; // current index for arrays
5754 while (pCur != NULL)
5756 _ASSERTE(iCur < pData->iHash);
5758 pData->arrClsId[iCur] = pCur->m_clsId;
5759 pData->arrcObjects[iCur] = (DWORD) pCur->m_count;
5761 // Move to the next entry
5763 pCur = (CLASSHASHENTRY *) pData->pHashTable->FindNextEntry(&hFind);
5766 _ASSERTE(iCur == pData->iHash);
5768 // Now communicate the results to the profiler
5770 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5771 // whose try/catch blocks aren't visible to the contract system
5772 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5773 return m_pCallback2->ObjectsAllocatedByClass((ULONG)pData->iHash, pData->arrClsId, pData->arrcObjects);
5777 HRESULT EEToProfInterfaceImpl::ObjectReference(ObjectID objId,
5780 ObjectID *arrObjRef)
5787 // This is called by the thread doing a GC WHILE it does the GC
5790 // This is called by the thread doing a GC WHILE it does the GC
5791 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5796 // Thread store lock normally held during this callback
5802 CLR_TO_PROFILER_ENTRYPOINT_EX(
5806 "**PROF: ObjectReferences.\n"));
5808 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5811 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5812 // whose try/catch blocks aren't visible to the contract system
5813 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5814 return m_pCallback2->ObjectReferences(objId, classId, cNumRefs, arrObjRef);
5819 HRESULT EEToProfInterfaceImpl::FinalizeableObjectQueued(BOOL isCritical, ObjectID objectID)
5829 // Can't be in preemptive when we're dealing in objectIDs!
5830 // However, it's possible we're on a non-EE Thread--that happens when this
5831 // is a server-mode GC thread.
5837 // Thread store lock normally held during this callback
5843 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5845 "**PROF: Notifying profiler of finalizeable object.\n"));
5847 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5850 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5851 // whose try/catch blocks aren't visible to the contract system
5852 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5853 return m_pCallback2->FinalizeableObjectQueued(isCritical ? COR_PRF_FINALIZER_CRITICAL : 0, objectID);
5858 HRESULT EEToProfInterfaceImpl::RootReferences2(GCReferencesData *pData)
5865 // This is called by the thread doing a GC WHILE it does the GC
5868 // This is called by the thread doing a GC WHILE it does the GC
5869 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5874 // Thread store lock normally held during this callback
5880 CLR_TO_PROFILER_ENTRYPOINT_EX(
5884 "**PROF: RootReferences2.\n"));
5886 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5890 COR_PRF_GC_ROOT_FLAGS flags[kcReferencesMax];
5892 _ASSERTE(pData->curIdx <= kcReferencesMax);
5893 for (ULONG i = 0; i < pData->curIdx; i++)
5895 flags[i] = (COR_PRF_GC_ROOT_FLAGS)(pData->arrULONG[i] & 0xffff);
5896 pData->arrULONG[i] >>= 16;
5900 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5901 // whose try/catch blocks aren't visible to the contract system
5902 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5903 hr = m_pCallback2->RootReferences2((ULONG)pData->curIdx,
5904 (ObjectID *)pData->arrpbMemBlockStartOld,
5905 (COR_PRF_GC_ROOT_KIND *)pData->arrULONG,
5907 (ObjectID *)pData->arrpbMemBlockStartNew);
5913 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5914 // whose try/catch blocks aren't visible to the contract system
5915 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5916 hr = m_pCallback2->RootReferences((ULONG)pData->curIdx, (ObjectID *)pData->arrpbMemBlockStartOld);
5923 HRESULT EEToProfInterfaceImpl::ConditionalWeakTableElementReferences(GCReferencesData * pData)
5930 // This is called by the thread doing a GC WHILE it does the GC
5933 // This is called by the thread doing a GC WHILE it does the GC
5934 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5939 // Thread store lock normally held during this callback
5945 CLR_TO_PROFILER_ENTRYPOINT_EX(
5949 "**PROF: ConditionalWeakTableElementReferences.\n"));
5951 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5955 _ASSERTE(pData->curIdx <= kcReferencesMax);
5958 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5959 // whose try/catch blocks aren't visible to the contract system
5960 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5961 hr = m_pCallback5->ConditionalWeakTableElementReferences(
5962 (ULONG)pData->curIdx,
5963 (ObjectID *)pData->arrpbMemBlockStartOld,
5964 (ObjectID *)pData->arrpbMemBlockStartNew,
5965 (GCHandleID *)pData->arrpbRootId);
5971 HRESULT EEToProfInterfaceImpl::HandleCreated(UINT_PTR handleId, ObjectID initialObjectId)
5978 // Called by HndCreateHandle which is notrigger
5981 // This can be called in preemptive mode if initialObjectId is NULL.
5982 // Otherwise, this will be in cooperative mode. Note that, although this
5983 // can be called in preemptive, when it's called in cooperative we must not
5984 // switch to preemptive (as we normally do in callbacks) and must not trigger,
5985 // as this would really tick off some of our callers (as well as invalidating
5986 // initialObjectId).
5987 if (initialObjectId != NULL)
5999 // CrstAppDomainHandleTable can be held during this callback
6005 CLR_TO_PROFILER_ENTRYPOINT_EX(
6009 "**PROF: HandleCreated.\n"));
6012 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6013 // whose try/catch blocks aren't visible to the contract system
6014 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6015 return m_pCallback2->HandleCreated(handleId, initialObjectId);
6019 HRESULT EEToProfInterfaceImpl::HandleDestroyed(UINT_PTR handleId)
6026 // Called by HndDestroyHandle, which is notrigger. But HndDestroyHandle is also
6027 // MODE_ANY, so perhaps we can change the whole call path to be triggers?
6030 // Although we're called from a notrigger function, I verified empirically that
6031 // this is called coop & preemp
6037 // Thread store lock is typically held during this callback
6043 CLR_TO_PROFILER_ENTRYPOINT_EX(
6047 "**PROF: HandleDestroyed.\n"));
6050 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6051 // whose try/catch blocks aren't visible to the contract system
6052 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6053 return m_pCallback2->HandleDestroyed(handleId);
6057 HRESULT EEToProfInterfaceImpl::GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason)
6064 // This is called by the thread doing a GC WHILE it does the GC
6067 // This is called by the thread doing a GC WHILE it does the GC
6068 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
6073 // Thread store lock normally held during this callback
6079 CLR_TO_PROFILER_ENTRYPOINT_EX(
6083 "**PROF: GarbageCollectionStarted.\n"));
6085 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6088 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6089 // whose try/catch blocks aren't visible to the contract system
6090 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6091 return m_pCallback2->GarbageCollectionStarted(cGenerations, generationCollected, reason);
6095 HRESULT EEToProfInterfaceImpl::GarbageCollectionFinished()
6102 // This is called by the thread doing a GC WHILE it does the GC
6105 // This is called by the thread doing a GC WHILE it does the GC
6106 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
6111 // Thread store lock normally held during this callback
6117 CLR_TO_PROFILER_ENTRYPOINT_EX(
6121 "**PROF: GarbageCollectionFinished.\n"));
6123 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6126 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6127 // whose try/catch blocks aren't visible to the contract system
6128 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6129 return m_pCallback2->GarbageCollectionFinished();
6133 HRESULT EEToProfInterfaceImpl::ProfilerDetachSucceeded()
6149 // ProfilingAPIUtility::s_csStatus is held while this callback is issued.
6155 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileDetaching,
6158 "**PROF: ProfilerDetachSucceeded.\n"));
6160 // Should only be called on profilers that support ICorProfilerCallback3
6161 _ASSERTE(m_pCallback3 != NULL);
6164 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6165 // whose try/catch blocks aren't visible to the contract system
6166 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6167 return m_pCallback3->ProfilerDetachSucceeded();
6171 #ifdef FEATURE_FUSION
6173 // Minimal wrappers so that Fusion can call the GetAssemblyReferences profiler callback
6174 // without needing a ton of profapi includes.
6176 BOOL ShouldCallGetAssemblyReferencesProfilerCallback()
6178 return CORProfilerAddsAssemblyReferences();
6181 void CallGetAssemblyReferencesProfilerCallbackIfNecessary(LPCWSTR wszAssemblyPath, IAssemblyBindingClosure * pClosure, AssemblyReferenceClosureWalkContextForProfAPI * pContext)
6183 BEGIN_PIN_PROFILER(CORProfilerAddsAssemblyReferences());
6184 g_profControlBlock.pProfInterface->GetAssemblyReferences(wszAssemblyPath, pClosure, pContext);
6188 // Implementation of ICorProfilerAssemblyReferenceProvider, which is given to the profiler so
6189 // that it can call back into the CLR with extra assembly references that should be considered
6190 // while Fusion performs its assembly reference closure walk.
6191 class ProfilerAssemblyReferenceProvider : public ICorProfilerAssemblyReferenceProvider
6194 // IUnknown functions
6195 virtual HRESULT __stdcall QueryInterface(REFIID id, void** pInterface)
6197 LIMITED_METHOD_CONTRACT;
6199 if (id == IID_IUnknown)
6201 *pInterface = static_cast<IUnknown *>(this);
6203 else if (id == IID_ICorProfilerAssemblyReferenceProvider)
6205 *pInterface = static_cast<ICorProfilerAssemblyReferenceProvider *>(this);
6210 return E_NOINTERFACE;
6217 virtual ULONG __stdcall AddRef()
6219 LIMITED_METHOD_CONTRACT;
6220 return InterlockedIncrement(&m_refCount);
6223 virtual ULONG __stdcall Release()
6225 LIMITED_METHOD_CONTRACT;
6227 ULONG refCount = InterlockedDecrement(&m_refCount);
6237 // ICorProfilerAssemblyReferenceProvider functions
6239 // This is what the profiler calls to tell us about an assembly reference we should include
6240 // when Fusion performs its closure walk. When this is called, the walk is already underway,
6241 // and is sitting on our stack already.
6242 virtual HRESULT __stdcall AddAssemblyReference(const COR_PRF_ASSEMBLY_REFERENCE_INFO * pAssemblyRefInfo)
6244 _ASSERTE(m_pClosure != NULL);
6246 return m_pClosure->AddProfilerAssemblyReference(
6247 pAssemblyRefInfo->pbPublicKeyOrToken,
6248 pAssemblyRefInfo->cbPublicKeyOrToken,
6249 pAssemblyRefInfo->szName,
6250 pAssemblyRefInfo->pMetaData,
6251 pAssemblyRefInfo->pbHashValue,
6252 pAssemblyRefInfo->cbHashValue,
6253 pAssemblyRefInfo->dwAssemblyRefFlags,
6258 ProfilerAssemblyReferenceProvider(IAssemblyBindingClosure * pClosure, AssemblyReferenceClosureWalkContextForProfAPI * pContext) :
6260 m_pClosure(pClosure),
6261 m_pContext(pContext)
6263 LIMITED_METHOD_CONTRACT;
6264 m_pClosure->AddRef();
6268 Volatile<LONG> m_refCount;
6270 // Our interface into Fusion's closure walk. We use this to inform Fusion about
6271 // the assembly reference the profiler gave us.
6272 ReleaseHolder<IAssemblyBindingClosure> m_pClosure;
6274 // Extra context built up by fusion's closure walk that we need to remember. The
6275 // walk is already in action by the time we're called, and this structure remembers
6276 // the lists that are getting built up by the walk
6277 AssemblyReferenceClosureWalkContextForProfAPI * m_pContext;
6280 #endif // FEATURE_FUSION
6283 HRESULT EEToProfInterfaceImpl::GetAssemblyReferences(LPCWSTR wszAssemblyPath, IAssemblyBindingClosure * pClosure, AssemblyReferenceClosureWalkContextForProfAPI * pContext)
6303 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
6305 "**PROF: AssemblyReferenceClosureWalkStarted. wszAssemblyPath: 0x%p.\n",
6310 #ifdef FEATURE_FUSION
6313 _ASSERTE(IsCallback6Supported());
6315 // Create an instance of the class implementing the interface we pass back to the profiler,
6316 // feeding it the context we're currently at in Fusion's closure walk
6317 ReleaseHolder<ProfilerAssemblyReferenceProvider> pReferenceProvider =
6318 new (nothrow) ProfilerAssemblyReferenceProvider(pClosure, pContext);
6319 if (pReferenceProvider == NULL)
6321 return E_OUTOFMEMORY;
6325 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6326 // whose try/catch blocks aren't visible to the contract system
6327 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6328 hr = m_pCallback6->GetAssemblyReferences(
6330 static_cast<ICorProfilerAssemblyReferenceProvider *>(pReferenceProvider));
6333 #endif // FEATURE_FUSION
6339 #endif // PROFILING_SUPPORTED