[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / eetoprofinterfaceimpl.cpp
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.
4 //
5 // EEToProfInterfaceImpl.cpp
6 // 
7
8 //
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.
12 //
13 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! 
15 //
16 // PLEASE READ!
17 //
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.
21 //
22 // As a reminder, here is a short summary of your responsibilities.  Every PUBLIC
23 // ENTRYPOINT (from EE to profiler) must have:
24 //
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
38 //          ThreadID).
39 //
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):
42 //       NOTHROW
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
48 //       GC_TRIGGERS
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.
51 //       CAN_TAKE_LOCK
52 //       ASSERT_NO_EE_LOCKS_HELD()
53 //   Note that the preferred contracts in this file are DIFFERENT than the preferred
54 //   contracts for proftoeeinterfaceimpl.cpp.
55 //
56 // Private helper functions in this file do not have the same preferred contracts as
57 // public entrypoints, and they should be contracted following the same guidelines
58 // as per the rest of the EE.
59 //
60 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! 
61 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
62 //
63
64 // ======================================================================================
65
66 #include "common.h"
67
68 #ifdef PROFILING_SUPPORTED
69
70
71 #include "eetoprofinterfaceimpl.h"
72 #include "eetoprofinterfaceimpl.inl"
73 #include "contract.h"
74 #include "proftoeeinterfaceimpl.h"
75 #include "proftoeeinterfaceimpl.inl"
76 #include "profilinghelper.inl"
77 #include "profdetach.h"
78 #include "simplerwlock.hpp"
79 #include "eeconfig.h"
80
81 //---------------------------------------------------------------------------------------
82 // Helpers
83
84 // Bitmask of flags that may be passed to the CLR_TO_PROFILER_ENTRYPOINT* macros
85 // to constrain when the callback may be issued
86 enum ClrToProfEntrypointFlags
87 {
88     // Default
89     kEE2PNone                           = 0x00000000,
90     
91     // Callback is allowable even for detaching profilers
92     kEE2PAllowableWhileDetaching        = 0x00000001,
93
94     // Callback is allowable even for initializing profilers
95     kEE2PAllowableWhileInitializing     = 0x00000002,
96
97     // Callback is made while in a GC_NOTRIGGER contract.  Whereas contracts are
98     // debug-only, this flag is used in retail builds as well.
99     kEE2PNoTrigger                      = 0x00000004,
100 };
101
102 #define ASSERT_EVAC_COUNTER_NONZERO()   \
103     _ASSERTE((GetThreadNULLOk() == NULL) ||                                             \
104              (GetThreadNULLOk()->GetProfilerEvacuationCounter() != 0U))
105
106 #define CHECK_PROFILER_STATUS(ee2pFlags)                                                \
107     /* If one of these asserts fires, perhaps you forgot to use                     */  \
108     /* BEGIN/END_PIN_PROFILER                                                       */  \
109     ASSERT_EVAC_COUNTER_NONZERO();                                                      \
110     _ASSERTE(g_profControlBlock.pProfInterface.Load() != NULL);                         \
111     _ASSERTE(g_profControlBlock.pProfInterface == this);                                \
112     /* Early abort if...                                                            */  \
113     if (                                                                                \
114         /* Profiler isn't active,                                                   */  \
115         !CORProfilerPresent() &&                                                        \
116                                                                                         \
117         /* and it's not the case that both a) this callback is allowed              */  \
118         /* on a detaching profiler, and b) the profiler is detaching                */  \
119         !(                                                                              \
120             (((ee2pFlags) & kEE2PAllowableWhileDetaching) != 0) &&                      \
121             (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching)            \
122          ) &&                                                                           \
123                                                                                         \
124         /* and it's not the case that both a) this callback is allowed              */  \
125         /* on an initializing profiler, and b) the profiler is initializing         */  \
126         !(                                                                              \
127             (((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) &&                   \
128             (                                                                           \
129               (g_profControlBlock.curProfStatus.Get()                                   \
130                   == kProfStatusInitializingForStartupLoad) ||                          \
131               (g_profControlBlock.curProfStatus.Get()                                   \
132                   == kProfStatusInitializingForAttachLoad)                              \
133             )                                                                           \
134          )                                                                              \
135        )                                                                                \
136     {                                                                                   \
137         return S_OK;                                                                    \
138     }
139
140 // Least common denominator for the callback wrappers.  Logs, records in EE Thread object
141 // that we're in a callback, and asserts that we're allowed to issue callbacks for the 
142 // specified ThreadID (i.e., no ThreadDestroyed callback has been issued for the 
143 // ThreadID).
144 // 
145 #define CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(ee2pFlags, threadId, logParams)        \
146     INCONTRACT(AssertTriggersContract(!((ee2pFlags) & kEE2PNoTrigger)));                \
147     CHECK_PROFILER_STATUS(ee2pFlags);                                                   \
148     LOG(logParams);                                                                     \
149     _ASSERTE(m_pCallback2 != NULL);                                                     \
150     /* Normally, set COR_PRF_CALLBACKSTATE_INCALLBACK |                              */ \
151     /* COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE in the callback state, but omit       */ \
152     /* COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE if we're in a GC_NOTRIGGERS callback  */ \
153     SetCallbackStateFlagsHolder __csf(                                                  \
154         (((ee2pFlags) & kEE2PNoTrigger) != 0) ?                                         \
155             COR_PRF_CALLBACKSTATE_INCALLBACK :                                          \
156             COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE  \
157         );                                                                              \
158     _ASSERTE(ProfilerCallbacksAllowedForThread((Thread *) (threadId)))
159
160 #define CLR_TO_PROFILER_ENTRYPOINT_EX(ee2pFlags, logParams)                             \
161     CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(ee2pFlags, GetThreadNULLOk(), logParams)
162
163 // Typical entrypoint macro you'll use. Checks that we're allowed to issue 
164 // callbacks for the current thread (i.e., no ThreadDestroyed callback has been 
165 // issued for the current thread).
166 #define CLR_TO_PROFILER_ENTRYPOINT(logParams)                                           \
167         CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PNone, logParams)
168 #define CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId, logParams)                      \
169         CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(kEE2PNone, threadId, logParams)
170
171
172 //---------------------------------------------------------------------------------------
173 //
174 // Wrapper around Thread::ProfilerCallbacksAllowed 
175 //
176 // Arguments:
177 //      pThread - Thread on which we need to determine whether callbacks are allowed
178 //
179 // Return Value:
180 //      TRUE if the profiler portion has marked this thread as allowable, else FALSE.
181 //
182
183 inline BOOL ProfilerCallbacksAllowedForThread(Thread * pThread)
184 {
185     WRAPPER_NO_CONTRACT;
186     return ((pThread == NULL) || (pThread->ProfilerCallbacksAllowed()));
187 }
188
189
190 //---------------------------------------------------------------------------------------
191 //
192 // Wrapper around Thread::SetProfilerCallbacksAllowed 
193 //
194 // Arguments:
195 //      pThread - Thread on which we're setting whether callbacks shall be allowed
196 //      fValue - The value to store.
197 //
198
199 inline void SetProfilerCallbacksAllowedForThread(Thread * pThread, BOOL fValue)
200 {
201     WRAPPER_NO_CONTRACT;
202     _ASSERTE(pThread != NULL);
203     pThread->SetProfilerCallbacksAllowed(fValue);
204 }
205
206
207 //---------------------------------------------------------------------------------------
208 //
209 // Low-level function to find and CoCreateInstance the profiler's DLL. Called when
210 // initializing via EEToProfInterfaceImpl::Init()
211 // 
212 // Arguments:
213 //      * pClsid - [in] Profiler's CLSID
214 //      * wszClsid - [in] String form of CLSID or progid of profiler to load.
215 //      * wszProfileDLL - [in] Path to profiler DLL
216 //      * ppCallback - [out] Pointer to profiler's ICorProfilerCallback2 interface
217 //      * phmodProfilerDLL - [out] HMODULE of profiler's DLL.
218 //          
219 // Return Value:
220 //    HRESULT indicating success or failure.
221 //    
222 // Notes:
223 //     * This function (or one of its callees) will log an error to the event log if
224 //         there is a failure
225
226 static HRESULT CoCreateProfiler(
227     const CLSID * pClsid,
228     __in_z LPCWSTR wszClsid, 
229     __in_z LPCWSTR wszProfileDLL,
230     ICorProfilerCallback2 ** ppCallback,
231     HMODULE * phmodProfilerDLL)
232 {
233     CONTRACTL
234     {
235         THROWS;
236         GC_TRIGGERS;
237         MODE_ANY;
238
239         // This causes events to be logged, which loads resource strings,
240         // which takes locks.
241         CAN_TAKE_LOCK;
242
243     } CONTRACTL_END;
244
245     _ASSERTE(pClsid != NULL);
246     _ASSERTE(wszClsid != NULL);
247     _ASSERTE(ppCallback != NULL);
248     _ASSERTE(phmodProfilerDLL != NULL);
249
250     LOG((LF_CORPROF, LL_INFO10, "**PROF: Entered CoCreateProfiler.\n"));
251
252     HRESULT hr;
253     *phmodProfilerDLL = NULL;
254
255     // This is the ICorProfilerCallback2 ptr we get back from the profiler's class
256     // factory's CreateInstance()
257     ReleaseHolder<ICorProfilerCallback2> pCallback2FromCreateInstance;
258     
259     // This is the ICorProfilerCallback2 ptr we get back from the profiler's QI (see its
260     // first use below for an explanation on why this is necessary).
261     ReleaseHolder<ICorProfilerCallback2> pCallback2FromQI;
262
263     // Create an instance of the profiler
264     hr = FakeCoCreateInstanceEx(*pClsid, 
265                                 wszProfileDLL,
266                                 IID_ICorProfilerCallback2, 
267                                 (LPVOID *) &pCallback2FromCreateInstance,
268                                 phmodProfilerDLL);
269
270     // (pCallback2FromCreateInstance == NULL) should be considered an error!
271     if ((pCallback2FromCreateInstance == NULL) && SUCCEEDED(hr))
272     {
273         hr = E_NOINTERFACE;
274     }
275
276     if (hr == E_NOINTERFACE)
277     {
278         // Helpful message for a potentially common problem
279         ProfilingAPIUtility::LogNoInterfaceError(IID_ICorProfilerCallback2, wszClsid);
280     }
281     else if (hr == CORPROF_E_PROFILER_CANCEL_ACTIVATION)
282     {
283         // Profiler didn't encounter a bad error, but is voluntarily choosing not to
284         // profile this runtime.  Profilers that need to set system environment
285         // variables to be able to profile services may use this HRESULT to avoid
286         // profiling all the other managed apps on the box.
287         ProfilingAPIUtility::LogProfInfo(IDS_PROF_CANCEL_ACTIVATION, wszClsid);
288     }
289     else if (FAILED(hr))
290     {
291         // Catch-all error for other CoCreateInstance failures
292         ProfilingAPIUtility::LogProfError(IDS_E_PROF_CCI_FAILED, wszClsid, hr);
293     }
294
295     // Now that hr is normalized (set to error if pCallback2FromCreateInstance == NULL),
296     // LOG and abort if there was a problem.
297     if (FAILED(hr))
298     {
299         LOG((
300             LF_CORPROF, 
301             LL_INFO10, 
302             "**PROF: Unable to CoCreateInstance profiler class %S.  hr=0x%x.\n",
303             wszClsid,
304             hr));
305         return hr;
306     }
307
308     // Redundantly QI for ICorProfilerCallback2.  This keeps CLR behavior consistent
309     // with Whidbey, and works around the following bug in some profilers' class factory
310     // CreateInstance:
311     //     * CreateInstance() ignores the IID it's given
312     //     * CreateInstance() returns a pointer to the object it created, even though
313     //         that object might not support the IID passed to CreateInstance().
314     // Whidbey CLR worked around this problem by redundantly QI'ing for the same IID
315     // again after CreateInstance() returned.  In this redudant QI, the profiler code would
316     // finally realize it didn't support that IID, and return an error there.  Without
317     // the redundant QI, the CLR would accept what it got from CreateInstance(), and
318     // start calling into it using the unsupported interface's vtable, which would
319     // cause an AV.
320     // 
321     // There were many MSDN samples (for example
322     // http://msdn.microsoft.com/msdnmag/issues/03/01/NETProfilerAPI/) which
323     // unfortunately had this CreateInstance() bug, so many profilers might have been
324     // generated based on this code.  Since it's easy & cheap to work around the
325     // problem, we do so here with the redundant QI.
326     hr = pCallback2FromCreateInstance->QueryInterface(
327         IID_ICorProfilerCallback2,
328         (LPVOID *) &pCallback2FromQI);
329
330     // (pCallback2FromQI == NULL) should be considered an error!
331     if ((pCallback2FromQI == NULL) && SUCCEEDED(hr))
332     {
333         hr = E_NOINTERFACE;
334     }
335
336     // Any error at this stage implies IID_ICorProfilerCallback2 is not supported
337     if (FAILED(hr))
338     {
339         // Helpful message for a potentially common problem
340         ProfilingAPIUtility::LogNoInterfaceError(IID_ICorProfilerCallback2, wszClsid);
341         return hr;
342     }
343
344     // Ok, safe to transfer ownership to caller's [out] param
345     *ppCallback = pCallback2FromQI.Extract();
346     pCallback2FromQI = NULL;
347
348     return S_OK;
349 }
350
351
352 //---------------------------------------------------------------------------------------
353 //
354 // Implementation of CHashTableImpl functions.  This class a simple implementation of
355 // CHashTable to provide a very simple implementation of the Cmp pure virtual function
356 //
357
358 EEToProfInterfaceImpl::CHashTableImpl::CHashTableImpl(ULONG iBuckets)
359     : CHashTable(iBuckets)
360 {
361     WRAPPER_NO_CONTRACT;
362 }
363
364 EEToProfInterfaceImpl::CHashTableImpl::~CHashTableImpl()
365 {
366     WRAPPER_NO_CONTRACT;
367 }
368
369 //---------------------------------------------------------------------------------------
370 //
371 // Comparison function for hash table of ClassIDs
372 //
373 // Arguments:
374 //      pc1 - hash key to compare
375 //      pc2 - hash value to compare
376 //
377 // Return Value:
378 //      TRUE if the key & value refer to the same ClassID; otherwise FALSE
379 //
380
381 BOOL EEToProfInterfaceImpl::CHashTableImpl::Cmp(SIZE_T k1, const HASHENTRY * pc2)
382 {
383     LIMITED_METHOD_CONTRACT;
384
385     ClassID key = (ClassID) k1;
386     ClassID val = ((CLASSHASHENTRY *)pc2)->m_clsId;
387
388     return (key != val);
389 }
390
391
392 //---------------------------------------------------------------------------------------
393 // Private maintenance functions for initialization, cleanup, etc.
394
395 EEToProfInterfaceImpl::AllocByClassData *EEToProfInterfaceImpl::m_pSavedAllocDataBlock = NULL;
396
397 //---------------------------------------------------------------------------------------
398 //
399 // EEToProfInterfaceImpl ctor just sets initial values
400 //
401
402 EEToProfInterfaceImpl::EEToProfInterfaceImpl() :
403     m_pCallback2(NULL),
404     m_pCallback3(NULL),
405     m_pCallback4(NULL),
406     m_pCallback5(NULL),
407     m_pCallback6(NULL),
408     m_pCallback7(NULL),
409     m_pCallback8(NULL),
410     m_pCallback9(NULL),
411     m_hmodProfilerDLL(NULL),
412     m_fLoadedViaAttach(FALSE),
413     m_pProfToEE(NULL),
414     m_pProfilersFuncIDMapper(NULL),
415     m_pProfilersFuncIDMapper2(NULL),
416     m_pProfilersFuncIDMapper2ClientData(NULL),
417     m_GUID(k_guidZero),
418     m_lGUIDCount(0),
419     m_pGCRefDataFreeList(NULL),
420     m_csGCRefDataFreeList(NULL),
421     m_pEnter(NULL),
422     m_pLeave(NULL),
423     m_pTailcall(NULL),
424     m_pEnter2(NULL),
425     m_pLeave2(NULL),
426     m_pTailcall2(NULL),
427     m_fIsClientIDToFunctionIDMappingEnabled(TRUE),
428     m_pEnter3(NULL),
429     m_pLeave3(NULL),
430     m_pTailcall3(NULL),
431     m_pEnter3WithInfo(NULL),
432     m_pLeave3WithInfo(NULL),
433     m_pTailcall3WithInfo(NULL),
434     m_fUnrevertiblyModifiedIL(FALSE),
435     m_fModifiedRejitState(FALSE),
436     m_pFunctionIDHashTable(NULL),
437     m_pFunctionIDHashTableRWLock(NULL),
438     m_dwConcurrentGCWaitTimeoutInMs(INFINITE),
439     m_bHasTimedOutWaitingForConcurrentGC(FALSE)
440 {
441     // Also NULL out this static.  (Note: consider making this a member variable.)
442     m_pSavedAllocDataBlock = NULL;
443     LIMITED_METHOD_CONTRACT;
444 }
445
446 //
447 //---------------------------------------------------------------------------------------
448 //
449 // Post-constructor initialization of EEToProfInterfaceImpl. Sets everything up,
450 // including creating the profiler.
451 //
452 // Parameters:
453 //      * pProfToEE - A newly-created ProfToEEInterfaceImpl instance that will be passed
454 //          to the profiler as the ICorProfilerInfo3 interface implementation.
455 //      * pClsid - Profiler's CLSID
456 //      * wszClsid - String form of CLSID or progid of profiler to load
457 //      * wszProfileDLL - Path to profiler DLL
458 //      * fLoadedViaAttach - TRUE iff the profiler is being attach-loaded (else
459 //             profiler is being startup-loaded)
460 //
461 // Return Value:
462 //      HRESULT indicating success or failure.
463 //
464 // Notes:
465 //      This function (or one of its callees) will log an error to the event log if there
466 //      is a failure
467 //
468
469
470 HRESULT EEToProfInterfaceImpl::Init(
471     ProfToEEInterfaceImpl * pProfToEE,
472     const CLSID * pClsid,
473     __in_z LPCWSTR wszClsid, 
474     __in_z LPCWSTR wszProfileDLL,
475     BOOL fLoadedViaAttach,
476     DWORD dwConcurrentGCWaitTimeoutInMs)
477 {
478     CONTRACTL
479     {
480         THROWS;
481         GC_TRIGGERS;
482         MODE_ANY;
483
484         // This causes events to be logged, which loads resource strings,
485         // which takes locks.
486         CAN_TAKE_LOCK;
487
488         MODE_PREEMPTIVE;
489     }
490     CONTRACTL_END;
491
492     HRESULT hr = E_UNEXPECTED;
493
494     _ASSERTE(pProfToEE != NULL);
495
496     m_fLoadedViaAttach = fLoadedViaAttach;
497     m_dwConcurrentGCWaitTimeoutInMs = dwConcurrentGCWaitTimeoutInMs;
498     
499     // The rule sez your Crst should switch to preemptive when it's taken.  We intentionally
500     // break this rule with CRST_UNSAFE_ANYMODE, because this Crst is taken DURING A GC
501     // (see AllocateMovedReferencesData(), called by MovedReference(), called by the GC),
502     // and we don't want to be switching modes in the middle of a GC!  Indeed, on server there
503     // may not even be a mode in the first place.
504     CRITSEC_AllocationHolder csGCRefDataFreeList(ClrCreateCriticalSection(CrstProfilerGCRefDataFreeList, CRST_UNSAFE_ANYMODE));
505     if (csGCRefDataFreeList == NULL)
506     {
507         LOG((LF_CORPROF, 
508             LL_ERROR, 
509             "**PROF: Failed to create Crst during initialization.\n"));
510
511         // A specialized event log entry for this failure would be confusing and
512         // unhelpful.  So just log a generic internal failure event
513         ProfilingAPIUtility::LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_FAIL);
514         return E_FAIL;
515     }
516
517     // CEEInfo::GetProfilingHandle will be PREEMPTIVE mode when trying to update 
518     // m_pFunctionIDHashTable while ProfileEnter, ProfileLeave and ProfileTailcall
519     // and LookupClientIDFromCache all will be in COOPERATIVE mode when trying 
520     // to read m_pFunctionIDHashTable, so pFunctionIDHashTableRWLock must be created 
521     // with COOPERATIVE_OR_PREEMPTIVE.  It is safe to so do because FunctionIDHashTable, 
522     // synchronized by m_pFunctionIDHashTableRWLock runs only native code and uses 
523     // only native heap.
524     NewHolder<SimpleRWLock> pFunctionIDHashTableRWLock(new (nothrow) SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT));
525
526     NewHolder<FunctionIDHashTable> pFunctionIDHashTable(new (nothrow) FunctionIDHashTable());
527
528     if ((pFunctionIDHashTable == NULL) || (pFunctionIDHashTableRWLock == NULL))
529     {
530         LOG((LF_CORPROF, 
531             LL_ERROR, 
532             "**PROF: Failed to create FunctionIDHashTable or FunctionIDHashTableRWLock during initialization.\n"));
533
534         // A specialized event log entry for this failure would be confusing and
535         // unhelpful.  So just log a generic internal failure event
536         ProfilingAPIUtility::LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_OUTOFMEMORY);
537
538         return E_OUTOFMEMORY;
539     }
540
541     // This wraps the following profiler calls in a try / catch:
542     // * ClassFactory::CreateInstance
543     // * AddRef/Release/QueryInterface
544     // Although most profiler calls are not protected, these creation calls are
545     // protected here since it's cheap to do so (this is only done once per load of a
546     // profiler), and it would be nice to avoid tearing down the entire process when
547     // attaching a profiler that may pass back bogus vtables.
548     EX_TRY
549     {
550         // CoCreate the profiler (but don't call its Initialize() method yet)
551         hr = CreateProfiler(pClsid, wszClsid, wszProfileDLL);
552     }
553     EX_CATCH
554     {
555         hr = E_UNEXPECTED;
556         ProfilingAPIUtility::LogProfError(IDS_E_PROF_UNHANDLED_EXCEPTION_ON_LOAD, wszClsid);
557     }
558     // Intentionally swallowing all exceptions, as we don't want a poorly-written
559     // profiler that throws or AVs on attach to cause the entire process to go away.
560     EX_END_CATCH(SwallowAllExceptions);
561
562
563     if (FAILED(hr))
564     {
565         // CreateProfiler (or catch clause above) has already logged an event to the
566         // event log on failure
567         return hr;
568     }
569
570     m_pProfToEE = pProfToEE;
571
572     m_csGCRefDataFreeList = csGCRefDataFreeList.Extract();
573     csGCRefDataFreeList = NULL;
574
575     m_pFunctionIDHashTable = pFunctionIDHashTable.Extract();
576     pFunctionIDHashTable = NULL;
577
578     m_pFunctionIDHashTableRWLock = pFunctionIDHashTableRWLock.Extract();
579     pFunctionIDHashTableRWLock = NULL;
580
581     return S_OK;
582 }
583
584
585 //---------------------------------------------------------------------------------------
586 //
587 // This is used by Init() to load the user-specified profiler (but not to call
588 // its Initialize() method).
589 //
590 // Arguments:
591 //      pClsid - Profiler's CLSID
592 //      wszClsid - String form of CLSID or progid of profiler to load
593 //      wszProfileDLL - Path to profiler DLL
594 //
595 // Return Value:
596 //    HRESULT indicating success / failure.  If this is successful, m_pCallback2 will be
597 //    set to the profiler's ICorProfilerCallback2 interface on return.  m_pCallback3,4
598 //    will be set to the profiler's ICorProfilerCallback3 interface on return if
599 //    ICorProfilerCallback3,4 is supported.
600 //
601 // Assumptions:
602 //    Although the profiler has not yet been instantiated, it is assumed that the internal
603 //    profiling API structures have already been created
604 //
605 // Notes:
606 //    This function (or one of its callees) will log an error to the event log
607 //    if there is a failure
608
609 HRESULT EEToProfInterfaceImpl::CreateProfiler(
610     const CLSID * pClsid,
611     __in_z LPCWSTR wszClsid, 
612     __in_z LPCWSTR wszProfileDLL)
613 {
614     CONTRACTL
615     {
616         THROWS;
617         GC_TRIGGERS;
618         MODE_ANY;
619
620         // This causes events to be logged, which loads resource strings,
621         // which takes locks.
622         CAN_TAKE_LOCK;
623
624         MODE_PREEMPTIVE;
625     } 
626     CONTRACTL_END;
627
628     // Always called before Thread created.
629     _ASSERTE(GetThreadNULLOk() == NULL);
630
631     // Try and CoCreate the registered profiler
632     ReleaseHolder<ICorProfilerCallback2> pCallback2;
633     HModuleHolder hmodProfilerDLL;
634     HRESULT hr = CoCreateProfiler(
635         pClsid,
636         wszClsid, 
637         wszProfileDLL, 
638         &pCallback2,
639         &hmodProfilerDLL);
640     if (FAILED(hr))
641     {
642         // CoCreateProfiler logs events to the event log on failures
643         return hr;
644     }
645
646     // CoCreateProfiler ensures that if it succeeds, we get some valid pointers
647     _ASSERTE(pCallback2 != NULL);
648     _ASSERTE(hmodProfilerDLL != NULL);
649     
650     // Save profiler pointers into this.  The reference ownership now
651     // belongs to this class, so NULL out locals without allowing them to release
652     m_pCallback2 = pCallback2.Extract();
653     pCallback2 = NULL;
654     m_hmodProfilerDLL = hmodProfilerDLL.Extract();
655     hmodProfilerDLL = NULL;
656
657     // The profiler may optionally support ICorProfilerCallback3,4,5,6,7,8,9.  Let's check.
658
659     ReleaseHolder<ICorProfilerCallback9> pCallback9;
660     hr = m_pCallback2->QueryInterface(
661         IID_ICorProfilerCallback9,
662         (LPVOID *)&pCallback9);
663     if (SUCCEEDED(hr) && (pCallback9 != NULL))
664     {
665         // Nifty.  Transfer ownership to this class
666         _ASSERTE(m_pCallback9 == NULL);
667         m_pCallback9 = pCallback9.Extract();
668         pCallback9 = NULL;
669
670         // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6,7,8
671         // due to inheritance relationship of the interfaces
672         _ASSERTE(m_pCallback8 == NULL);
673         m_pCallback8 = static_cast<ICorProfilerCallback8 *>(m_pCallback9);
674         m_pCallback8->AddRef();
675
676         _ASSERTE(m_pCallback7 == NULL);
677         m_pCallback7 = static_cast<ICorProfilerCallback7 *>(m_pCallback8);
678         m_pCallback7->AddRef();
679
680         _ASSERTE(m_pCallback6 == NULL);
681         m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
682         m_pCallback6->AddRef();
683
684         _ASSERTE(m_pCallback5 == NULL);
685         m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
686         m_pCallback5->AddRef();
687
688         _ASSERTE(m_pCallback4 == NULL);
689         m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
690         m_pCallback4->AddRef();
691
692         _ASSERTE(m_pCallback3 == NULL);
693         m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
694         m_pCallback3->AddRef();
695     }
696
697     if (m_pCallback8 == NULL)
698     {
699         ReleaseHolder<ICorProfilerCallback8> pCallback8;
700         hr = m_pCallback2->QueryInterface(
701             IID_ICorProfilerCallback8,
702             (LPVOID *)&pCallback8);
703         if (SUCCEEDED(hr) && (pCallback8 != NULL))
704         {
705             // Nifty.  Transfer ownership to this class
706             _ASSERTE(m_pCallback8 == NULL);
707             m_pCallback8 = pCallback8.Extract();
708             pCallback8 = NULL;
709
710             // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6,7
711             // due to inheritance relationship of the interfaces
712
713             _ASSERTE(m_pCallback7 == NULL);
714             m_pCallback7 = static_cast<ICorProfilerCallback7 *>(m_pCallback8);
715             m_pCallback7->AddRef();
716
717             _ASSERTE(m_pCallback6 == NULL);
718             m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
719             m_pCallback6->AddRef();
720
721             _ASSERTE(m_pCallback5 == NULL);
722             m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
723             m_pCallback5->AddRef();
724
725             _ASSERTE(m_pCallback4 == NULL);
726             m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
727             m_pCallback4->AddRef();
728
729             _ASSERTE(m_pCallback3 == NULL);
730             m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
731             m_pCallback3->AddRef();
732         }
733     }
734
735     if (m_pCallback7 == NULL)
736     {
737         ReleaseHolder<ICorProfilerCallback7> pCallback7;
738         hr = m_pCallback2->QueryInterface(
739             IID_ICorProfilerCallback7,
740             (LPVOID *)&pCallback7);
741         if (SUCCEEDED(hr) && (pCallback7 != NULL))
742         {
743             // Nifty.  Transfer ownership to this class
744             _ASSERTE(m_pCallback7 == NULL);
745             m_pCallback7 = pCallback7.Extract();
746             pCallback7 = NULL;
747
748             // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6
749             // due to inheritance relationship of the interfaces
750
751             _ASSERTE(m_pCallback6 == NULL);
752             m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
753             m_pCallback6->AddRef();
754
755             _ASSERTE(m_pCallback5 == NULL);
756             m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
757             m_pCallback5->AddRef();
758
759             _ASSERTE(m_pCallback4 == NULL);
760             m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
761             m_pCallback4->AddRef();
762
763             _ASSERTE(m_pCallback3 == NULL);
764             m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
765             m_pCallback3->AddRef();
766         }
767     }
768
769     if (m_pCallback6 == NULL)
770     {
771         ReleaseHolder<ICorProfilerCallback6> pCallback6;
772         hr = m_pCallback2->QueryInterface(
773             IID_ICorProfilerCallback6,
774             (LPVOID *)&pCallback6);
775         if (SUCCEEDED(hr) && (pCallback6 != NULL))
776         {
777             // Nifty.  Transfer ownership to this class
778             _ASSERTE(m_pCallback6 == NULL);
779             m_pCallback6 = pCallback6.Extract();
780             pCallback6 = NULL;
781
782             // And while we're at it, we must now also have an ICorProfilerCallback3,4,5
783             // due to inheritance relationship of the interfaces
784
785             _ASSERTE(m_pCallback5 == NULL);
786             m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
787             m_pCallback5->AddRef();
788
789             _ASSERTE(m_pCallback4 == NULL);
790             m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
791             m_pCallback4->AddRef();
792
793             _ASSERTE(m_pCallback3 == NULL);
794             m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
795             m_pCallback3->AddRef();
796         }
797     }
798         
799     if (m_pCallback5 == NULL)
800     {
801         ReleaseHolder<ICorProfilerCallback5> pCallback5;
802         hr = m_pCallback2->QueryInterface(
803             IID_ICorProfilerCallback5,
804             (LPVOID *) &pCallback5);
805         if (SUCCEEDED(hr) && (pCallback5 != NULL))
806         {
807             // Nifty.  Transfer ownership to this class
808             _ASSERTE(m_pCallback5 == NULL);
809             m_pCallback5 = pCallback5.Extract();
810             pCallback5 = NULL;
811
812             // And while we're at it, we must now also have an ICorProfilerCallback3, and
813             // ICorProfilerCallback4 due to inheritance relationship of the interfaces
814             _ASSERTE(m_pCallback4 == NULL);
815             m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
816             m_pCallback4->AddRef();
817
818             _ASSERTE(m_pCallback3 == NULL);
819             m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
820             m_pCallback3->AddRef();
821         }
822     }
823
824     if (m_pCallback4 == NULL)
825     {
826         ReleaseHolder<ICorProfilerCallback4> pCallback4;
827         hr = m_pCallback2->QueryInterface(
828             IID_ICorProfilerCallback4,
829             (LPVOID *) &pCallback4);
830         if (SUCCEEDED(hr) && (pCallback4 != NULL))
831         {
832             // Nifty.  Transfer ownership to this class
833             _ASSERTE(m_pCallback4 == NULL);
834             m_pCallback4 = pCallback4.Extract();
835             pCallback4 = NULL;
836
837             // And while we're at it, we must now also have an ICorProfilerCallback3, and
838             // due to inheritance relationship of the interfaces
839             _ASSERTE(m_pCallback3 == NULL);
840             m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
841             m_pCallback3->AddRef();
842         }
843     }
844
845     if (m_pCallback3 == NULL)
846     {
847         ReleaseHolder<ICorProfilerCallback3> pCallback3;
848         hr = m_pCallback2->QueryInterface(
849             IID_ICorProfilerCallback3,
850             (LPVOID *) &pCallback3);
851         if (SUCCEEDED(hr) && (pCallback3 != NULL))
852         {
853             // Nifty.  Transfer ownership to this class
854             _ASSERTE(m_pCallback3 == NULL);
855             m_pCallback3 = pCallback3.Extract();
856             pCallback3 = NULL;
857         }
858     }
859
860     return S_OK;
861 }
862
863
864
865
866 //---------------------------------------------------------------------------------------
867 //
868 // Performs cleanup for EEToProfInterfaceImpl, including releasing the profiler's 
869 // callback interface.  Called on termination of a profiler connection.
870 //
871
872 EEToProfInterfaceImpl::~EEToProfInterfaceImpl()
873 {
874     CONTRACTL
875     {
876         NOTHROW;
877         GC_NOTRIGGER;
878         MODE_ANY;
879
880         // When we release the profiler's callback interface
881         // below, it may well perform cleanup that takes locks.
882         // Example:  profiler may release a metadata interface, which
883         // causes it to take a reader lock
884         CAN_TAKE_LOCK;
885     }
886     CONTRACTL_END;
887
888     // Make sure there's no pointer about to dangle once we disappear.
889     // FUTURE: For reattach-with-neutered-profilers feature crew, change this assert to
890     // scan through list of detaching profilers to make sure none of them give a
891     // GetEEToProfPtr() equal to this
892 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
893     _ASSERTE(ProfilingAPIDetach::GetEEToProfPtr() == NULL);
894 #endif // FEATURE_PROFAPI_ATTACH_DETACH
895
896     // Release user-specified profiler DLL
897     // NOTE: If we're tearing down the process, then do nothing related
898     // to cleaning up the profiler DLL, as the DLL may no longer
899     // be present.
900     if (!IsAtProcessExit())
901     {
902         if (m_pCallback2 != NULL)
903         {
904             m_pCallback2->Release();
905             m_pCallback2 = NULL;
906         }
907
908         BOOL fIsV4Profiler = (m_pCallback3 != NULL);
909
910         if (fIsV4Profiler)
911         {
912             m_pCallback3->Release();
913             m_pCallback3 = NULL;
914         }
915
916         if (m_pCallback4 != NULL)
917         {
918             m_pCallback4->Release();
919             m_pCallback4 = NULL;
920         }
921
922         if (m_pCallback5 != NULL)
923         {
924             m_pCallback5->Release();
925             m_pCallback5 = NULL;
926         }
927
928         if (m_pCallback6 != NULL)
929         {
930             m_pCallback6->Release();
931             m_pCallback6 = NULL;
932         }
933
934         if (m_pCallback7 != NULL)
935         {
936             m_pCallback7->Release();
937             m_pCallback7 = NULL;
938         }
939
940         if (m_pCallback8 != NULL)
941         {
942             m_pCallback8->Release();
943             m_pCallback8 = NULL;
944         }
945
946         if (m_pCallback9 != NULL)
947         {
948             m_pCallback9->Release();
949             m_pCallback9 = NULL;
950         }
951
952         // Only unload the V4 profiler if this is not part of shutdown.  This protects
953         // Whidbey profilers that aren't used to being FreeLibrary'd.
954         if (fIsV4Profiler && !g_fEEShutDown)
955         {
956             if (m_hmodProfilerDLL != NULL)
957             {
958                 FreeLibrary(m_hmodProfilerDLL);
959                 m_hmodProfilerDLL = NULL;
960             }
961
962             // Now that the profiler is destroyed, it is no longer referencing our
963             // ProfToEEInterfaceImpl, so it's safe to destroy that, too.
964             if (m_pProfToEE != NULL)
965             {
966                 delete m_pProfToEE;
967                 m_pProfToEE = NULL;
968             }
969         }
970     }
971
972     // Delete the structs associated with GC moved references
973     while (m_pGCRefDataFreeList)
974     {
975         GCReferencesData * pDel = m_pGCRefDataFreeList;
976         m_pGCRefDataFreeList = m_pGCRefDataFreeList->pNext;
977         delete pDel;
978     }
979
980     if (m_pSavedAllocDataBlock)
981     {
982 #ifdef _WIN64
983         _ASSERTE((UINT_PTR)m_pSavedAllocDataBlock != 0xFFFFFFFFFFFFFFFF);
984 #else
985         _ASSERTE((UINT_PTR)m_pSavedAllocDataBlock != 0xFFFFFFFF);
986 #endif
987
988         _ASSERTE(m_pSavedAllocDataBlock->pHashTable != NULL);
989         // Get rid of the hash table
990         if (m_pSavedAllocDataBlock->pHashTable)
991             delete m_pSavedAllocDataBlock->pHashTable;
992
993         // Get rid of the two arrays used to hold class<->numinstance info
994         if (m_pSavedAllocDataBlock->cLength != 0)
995         {
996             _ASSERTE(m_pSavedAllocDataBlock->arrClsId != NULL);
997             _ASSERTE(m_pSavedAllocDataBlock->arrcObjects != NULL);
998
999             delete [] m_pSavedAllocDataBlock->arrClsId;
1000             delete [] m_pSavedAllocDataBlock->arrcObjects;
1001         }
1002
1003         // Get rid of the hash array used by the hash table
1004         if (m_pSavedAllocDataBlock->arrHash)
1005         {
1006             delete [] m_pSavedAllocDataBlock->arrHash;
1007         }
1008
1009         m_pSavedAllocDataBlock = NULL;
1010     }
1011
1012     m_GUID = k_guidZero;
1013
1014     if (m_csGCRefDataFreeList != NULL)
1015     {
1016         ClrDeleteCriticalSection(m_csGCRefDataFreeList);
1017         m_csGCRefDataFreeList = NULL;
1018     }
1019
1020     if (m_pFunctionIDHashTable != NULL)
1021     {
1022         delete m_pFunctionIDHashTable;
1023         m_pFunctionIDHashTable = NULL;
1024     }
1025     
1026     if (m_pFunctionIDHashTableRWLock != NULL)
1027     {
1028         delete m_pFunctionIDHashTableRWLock;
1029         m_pFunctionIDHashTableRWLock = NULL;
1030     }
1031 }
1032
1033
1034
1035 //---------------------------------------------------------------------------------------
1036 //
1037 // Initialize the GUID used for the cookie in remoting callbacks.  If already
1038 // initialized, this just does nothing and returns S_OK.
1039 //
1040 // Return Value:
1041 //      HRESULT indicating success or failure.  If the GUID was already initialized,
1042 //      just returns S_OK
1043 //
1044 //
1045
1046 HRESULT EEToProfInterfaceImpl::InitGUID()
1047 {
1048     CONTRACTL
1049     {
1050         NOTHROW;
1051         GC_NOTRIGGER;
1052         CANNOT_TAKE_LOCK;
1053         ASSERT_NO_EE_LOCKS_HELD();
1054     }
1055     CONTRACTL_END;
1056
1057     if (IsEqualGUID(m_GUID, k_guidZero))
1058     {
1059         return CoCreateGuid(&m_GUID);
1060     }
1061
1062     return S_OK;
1063 }
1064
1065 //---------------------------------------------------------------------------------------
1066 //
1067 // Returns a GUID suitable for use as a remoting callback cookie for this thread.
1068 // The GUID is based on the template GUID (m_GUID), the current thread, and
1069 // a counter.
1070 //
1071 // Arguments:
1072 //      pGUID - [out] The GUID requested
1073 //
1074
1075 void EEToProfInterfaceImpl::GetGUID(GUID * pGUID)
1076 {
1077     CONTRACTL
1078     {
1079         NOTHROW;
1080         GC_NOTRIGGER;
1081         ASSERT_NO_EE_LOCKS_HELD();
1082     }
1083     CONTRACTL_END;
1084     
1085     // the member GUID and the argument should both be valid
1086     _ASSERTE(!(IsEqualGUID(m_GUID, k_guidZero)));
1087     _ASSERTE(pGUID); 
1088
1089     // Copy the contents of the template GUID
1090     memcpy(pGUID, &m_GUID, sizeof(GUID));
1091
1092     // Adjust the last two bytes
1093     pGUID->Data4[6] = (BYTE) GetCurrentThreadId();
1094     pGUID->Data4[7] = (BYTE) InterlockedIncrement((LPLONG)&m_lGUIDCount);
1095 }
1096
1097 //---------------------------------------------------------------------------------------
1098 //
1099 // Wrapper around calling profiler's FunctionIDMapper hook.  Called by JIT.
1100 //
1101 // Arguments:
1102 //      funcId - FunctionID for profiler to map
1103 //      pbHookFunction - [out] Specifies whether the profiler wants to hook (enter/leave)
1104 //                             this function 
1105 //
1106 // Return Value:
1107 //      The profiler-specified value that we should use to identify this function
1108 //      in future hooks (enter/leave).
1109 //      If the remapped ID returned by the profiler is NULL, we will replace it with
1110 //      funcId.  Thus, this function will never return NULL.
1111 //
1112
1113 UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction)
1114 {
1115     // This isn't a public callback via ICorProfilerCallback*, but it's close (a
1116     // public callback via a function pointer).  So we'll aim to have the preferred
1117     // contracts here.
1118     CONTRACTL 
1119     {
1120         // Yay!
1121         NOTHROW;
1122
1123         // Yay!
1124         GC_TRIGGERS;
1125
1126         // Yay!
1127         MODE_PREEMPTIVE;
1128
1129         // Yay!
1130         CAN_TAKE_LOCK;
1131
1132         // ListLockEntry typically held during this callback (thanks to
1133         // MethodTable::DoRunClassInitThrowing).
1134
1135     } 
1136     CONTRACTL_END;
1137    
1138     // only called when CORProfilerFunctionIDMapperEnabled() is true, 
1139     // which means either m_pProfilersFuncIDMapper or m_pProfilersFuncIDMapper2 should not be NULL;
1140     _ASSERTE((m_pProfilersFuncIDMapper != NULL) || (m_pProfilersFuncIDMapper2 != NULL));
1141    
1142     UINT_PTR clientId = NULL;
1143
1144     if (m_pProfilersFuncIDMapper2 != NULL)
1145     {
1146         CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
1147                                     LL_INFO100, 
1148                                     "**PROF: Calling profiler's FunctionIDMapper2. funcId: 0x%p. clientData: 0x%p.\n", 
1149                                     funcId,
1150                                     m_pProfilersFuncIDMapper2ClientData));
1151
1152         // The attached profiler may not want to hook this function, so ask it 
1153         clientId = m_pProfilersFuncIDMapper2(funcId, m_pProfilersFuncIDMapper2ClientData, pbHookFunction);
1154
1155     }
1156     else
1157     {
1158         CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
1159                                     LL_INFO100, 
1160                                     "**PROF: Calling profiler's FunctionIDMapper. funcId: 0x%p.\n", 
1161                                     funcId));
1162
1163         // The attached profiler may not want to hook this function, so ask it 
1164         clientId = m_pProfilersFuncIDMapper(funcId, pbHookFunction);
1165     }
1166     
1167     static LONG s_lIsELT2Enabled = -1;
1168     if (s_lIsELT2Enabled == -1)
1169     {
1170         LONG lEnabled = ((m_pEnter2    != NULL) || 
1171                          (m_pLeave2    != NULL) || 
1172                          (m_pTailcall2 != NULL));
1173
1174         InterlockedCompareExchange(&s_lIsELT2Enabled, lEnabled, -1);
1175     }
1176
1177     // We need to keep track the mapping between ClientID and FunctionID for ELT2
1178     if (s_lIsELT2Enabled != 0)
1179     {
1180         FunctionIDAndClientID functionIDAndClientID;
1181         functionIDAndClientID.functionID = funcId;
1182         functionIDAndClientID.clientID   = clientId;
1183
1184         // ClientID Hash table may throw OUTOFMEMORY exception, which is not expected by the caller.
1185         EX_TRY 
1186         {
1187             SimpleWriteLockHolder writeLockHolder(m_pFunctionIDHashTableRWLock);
1188             m_pFunctionIDHashTable->AddOrReplace(functionIDAndClientID);
1189         } 
1190         EX_CATCH 
1191         {
1192             // Running out of heap memory means we no longer can maintain the integrity of the mapping table.
1193             // All ELT2 fast-path hooks are disabled since we cannot report correct FunctionID to the
1194             // profiler at this moment.
1195             m_fIsClientIDToFunctionIDMappingEnabled = FALSE;
1196         }
1197         EX_END_CATCH(RethrowTerminalExceptions);
1198
1199         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
1200         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
1201         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
1202         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
1203         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
1204         return funcId;
1205     }
1206
1207     // For profilers that support ELT3, clientID will be embedded into the ELT3 probes 
1208     return clientId;
1209 }
1210
1211
1212 //---------------------------------------------------------------------------------------
1213 //
1214 // Private functions called by GC so we can cache data for later notification to
1215 // the profiler
1216 //
1217
1218 //---------------------------------------------------------------------------------------
1219 //
1220 // Called lazily to allocate or use a recycled GCReferencesData.
1221 //
1222 // Return Value:
1223 //      GCReferencesData * requested by caller.
1224 //
1225 // Notes:
1226 //      Uses m_csGCRefDataFreeList to find a recycleable GCReferencesData
1227 //      Called by GC callbacks that need to record GC references reported
1228 //          to the callbacks by the GC as the GC walks the heap.
1229 //
1230
1231 EEToProfInterfaceImpl::GCReferencesData * EEToProfInterfaceImpl::AllocateMovedReferencesData()
1232 {
1233     CONTRACTL
1234     {
1235         NOTHROW;
1236         GC_NOTRIGGER;
1237         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
1238
1239         // We directly take m_csGCRefDataFreeList around accessing the free list below
1240         CAN_TAKE_LOCK;
1241
1242         // Thread store lock normally held during this call
1243     }
1244     CONTRACTL_END;
1245
1246     GCReferencesData *pData = NULL;
1247
1248     // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1249     {
1250         CRITSEC_Holder csh(m_csGCRefDataFreeList);
1251
1252         // Anything on the free list for us to grab?
1253         if (m_pGCRefDataFreeList != NULL)
1254         {
1255             // Yup, get the first element from the free list
1256             pData = m_pGCRefDataFreeList;
1257             m_pGCRefDataFreeList = m_pGCRefDataFreeList->pNext;
1258         }
1259     }
1260
1261     if (pData == NULL)
1262     {
1263         // Still not set, so the free list must not have had anything
1264         // available.  Go ahead and allocate a struct directly.
1265         pData = new (nothrow) GCReferencesData;
1266         if (!pData)
1267         {
1268             return NULL;
1269         }
1270     }
1271
1272     // Now init the new block
1273     _ASSERTE(pData != NULL);
1274
1275     // Set our index to the beginning
1276     pData->curIdx = 0;
1277     pData->compactingCount = 0;
1278
1279     return pData;
1280 }
1281
1282 //---------------------------------------------------------------------------------------
1283 //
1284 // After reporting references to the profiler, this recycles the GCReferencesData
1285 // that was used.  See EEToProfInterfaceImpl::EndRootReferences2.
1286 //
1287 // Arguments:
1288 //      pData - Pointer to GCReferencesData to recycle
1289 //
1290
1291 void EEToProfInterfaceImpl::FreeMovedReferencesData(GCReferencesData * pData)
1292 {
1293     CONTRACTL
1294     {
1295         NOTHROW;
1296         GC_NOTRIGGER;
1297         MODE_ANY;
1298
1299         // We directly take m_csGCRefDataFreeList around accessing the free list below
1300         CAN_TAKE_LOCK;
1301
1302         // Thread store lock normally held during this callback
1303
1304     }
1305     CONTRACTL_END;
1306
1307     // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1308     {
1309         CRITSEC_Holder csh(m_csGCRefDataFreeList);
1310         pData->pNext = m_pGCRefDataFreeList;
1311         m_pGCRefDataFreeList = pData;
1312     }
1313 }
1314
1315 //---------------------------------------------------------------------------------------
1316 //
1317 // Called by the GC to notify profapi of a moved reference.  We cache the
1318 // info here so we can later notify the profiler of all moved references
1319 // in bulk.
1320 //
1321 // Arguments:
1322 //      pbMemBlockStart - Start of moved block
1323 //      pbMemBlockEnd - End of moved block
1324 //      cbRelocDistance - Offset from pbMemBlockStart of where the block
1325 //                        was moved to
1326 //      pHeapId - GCReferencesData * used to record the block
1327 //      fCompacting - Is this a compacting collection?
1328 //
1329 // Return Value:
1330 //      HRESULT indicating success or failure
1331 //
1332
1333 HRESULT EEToProfInterfaceImpl::MovedReference(BYTE * pbMemBlockStart,
1334                                               BYTE * pbMemBlockEnd,
1335                                               ptrdiff_t cbRelocDistance,
1336                                               void * pHeapId,
1337                                               BOOL fCompacting)
1338 {
1339     CONTRACTL
1340     {
1341         NOTHROW;
1342
1343         // Called during a GC
1344         GC_NOTRIGGER;
1345         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
1346
1347         // Thread store lock normally held during this callback
1348     }
1349     CONTRACTL_END;
1350     
1351     _ASSERTE(pHeapId);
1352     _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1353
1354     // Get a pointer to the data for this heap
1355     GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1356
1357     // If this is the first notification of a moved reference for this heap
1358     // in this particular gc activation, then we need to get a ref data block
1359     // from the free list of blocks, or if that's empty then we need to
1360     // allocate a new one.
1361     if (pData == NULL)
1362     {
1363         pData = AllocateMovedReferencesData();
1364         if (pData == NULL)
1365         {
1366             return E_OUTOFMEMORY;
1367         }
1368
1369         // Set the cookie so that we will be provided it on subsequent
1370         // callbacks
1371         ((*((size_t *)pHeapId))) = (size_t)pData;
1372     }
1373
1374     _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1375
1376     // If the struct has been filled, then we need to notify the profiler of
1377     // these moved references and clear the struct for the next load of
1378     // moved references
1379     if (pData->curIdx == kcReferencesMax)
1380     {
1381         MovedReferences(pData);
1382         pData->curIdx = 0;
1383         pData->compactingCount = 0;
1384     }
1385
1386     // Now save the information in the struct
1387     pData->arrpbMemBlockStartOld[pData->curIdx] = pbMemBlockStart;
1388     pData->arrpbMemBlockStartNew[pData->curIdx] = pbMemBlockStart + cbRelocDistance;
1389     pData->arrMemBlockSize[pData->curIdx] = pbMemBlockEnd - pbMemBlockStart;
1390
1391     // Increment the index into the parallel arrays
1392     pData->curIdx += 1;
1393
1394     // Keep track of whether this is a compacting collection
1395     if (fCompacting)
1396     {
1397         pData->compactingCount += 1;
1398         // The gc is supposed to make up its mind whether this is a compacting collection or not
1399         // Thus if this one is compacting, everything so far had to say compacting
1400         _ASSERTE(pData->compactingCount == pData->curIdx);
1401     }
1402     else
1403     {
1404         // The gc is supposed to make up its mind whether this is a compacting collection or not
1405         // Thus if this one is non-compacting, everything so far had to say non-compacting
1406         _ASSERTE(pData->compactingCount == 0 && cbRelocDistance == 0);
1407     }
1408     return (S_OK);
1409 }
1410
1411 //---------------------------------------------------------------------------------------
1412 //
1413 // Called by the GC to indicate that the GC is finished calling
1414 // EEToProfInterfaceImpl::MovedReference for this collection.  This function will
1415 // call into the profiler to notify it of all the moved references we've cached.
1416 //
1417 // Arguments:
1418 //      pHeapId - Casted to a GCReferencesData * that contains the moved reference
1419 //                data we've cached.
1420 //
1421 // Return Value:
1422 //      HRESULT indicating success or failure.
1423 //
1424
1425 HRESULT EEToProfInterfaceImpl::EndMovedReferences(void * pHeapId)
1426 {
1427     CONTRACTL
1428     {
1429         NOTHROW;
1430
1431         // Called during a GC
1432         GC_NOTRIGGER;
1433         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
1434
1435         // We directly take m_csGCRefDataFreeList around accessing the free list below
1436         CAN_TAKE_LOCK;
1437
1438         // Thread store lock normally held during this callback
1439     }
1440     CONTRACTL_END;
1441
1442     _ASSERTE(pHeapId);
1443     _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1444
1445     HRESULT hr = S_OK;
1446
1447     // Get a pointer to the data for this heap
1448     GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1449
1450     // If there were no moved references, profiler doesn't need to know
1451     if (!pData)
1452         return (S_OK);
1453
1454     // Communicate the moved references to the profiler
1455     _ASSERTE(pData->curIdx> 0);
1456     hr = MovedReferences(pData);
1457
1458     // Now we're done with the data block, we can shove it onto the free list
1459     // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1460     {
1461         CRITSEC_Holder csh(m_csGCRefDataFreeList);
1462         pData->pNext = m_pGCRefDataFreeList;
1463         m_pGCRefDataFreeList = pData;
1464     }
1465
1466 #ifdef _DEBUG
1467     // Set the cookie to an invalid number
1468     (*((size_t *)pHeapId)) = (size_t)(-1);
1469 #endif // _DEBUG
1470
1471     return (hr);
1472 }
1473
1474
1475 #define HASH_ARRAY_SIZE_INITIAL 1024
1476 #define HASH_ARRAY_SIZE_INC     256
1477 #define HASH_NUM_BUCKETS        32
1478 #define HASH(x)       ( (ULONG) ((SIZE_T)x) )  // A simple hash function
1479
1480 //---------------------------------------------------------------------------------------
1481 //
1482 // Callback used by the GC when walking the heap (via AllocByClassHelper in
1483 // ProfToEEInterfaceImpl.cpp).
1484 //
1485 // Arguments:
1486 //      objId - Object reference encountered during heap walk
1487 //      classId - ClassID for objID
1488 //      pHeapId - heap walk context used by this function; it's interpreted
1489 //                as an AllocByClassData * to keep track of objects on the
1490 //                heap by class.
1491 //
1492 // Return Value:
1493 //      HRESULT indicating whether to continue with the heap walk (i.e.,
1494 //      success HRESULT) or abort it (i.e., failure HRESULT).
1495 //
1496
1497 HRESULT EEToProfInterfaceImpl::AllocByClass(ObjectID objId, ClassID clsId, void * pHeapId)
1498 {
1499     CONTRACTL
1500     {
1501         NOTHROW;
1502         GC_NOTRIGGER;
1503         MODE_ANY;
1504     }
1505     CONTRACTL_END;
1506
1507 #ifdef _DEBUG
1508     // This is a slight attempt to make sure that this is never called in a multi-threaded
1509     // manner.  This heap walk should be done by one thread at a time only.
1510     static DWORD dwProcId = 0xFFFFFFFF;
1511 #endif
1512
1513     _ASSERTE(pHeapId != NULL);
1514     _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1515
1516     // The heapId they pass in is really a AllocByClassData struct ptr.
1517     AllocByClassData *pData = (AllocByClassData *)(*((size_t *)pHeapId));
1518
1519     // If it's null, need to allocate one
1520     if (pData == NULL)
1521     {
1522 #ifdef _DEBUG
1523         // This is a slight attempt to make sure that this is never called in a multi-threaded
1524         // manner.  This heap walk should be done by one thread at a time only.
1525         dwProcId = GetCurrentProcessId();
1526 #endif
1527
1528         // See if we've saved a data block from a previous GC
1529         if (m_pSavedAllocDataBlock != NULL)
1530             pData = m_pSavedAllocDataBlock;
1531
1532         // This means we need to allocate all the memory to keep track of the info
1533         else
1534         {
1535             // Get a new alloc data block
1536             pData = new (nothrow) AllocByClassData;
1537             if (pData == NULL)
1538                 return (E_OUTOFMEMORY);
1539
1540             // Create a new hash table
1541             pData->pHashTable = new (nothrow) CHashTableImpl(HASH_NUM_BUCKETS);
1542             if (!pData->pHashTable)
1543             {
1544                 delete pData;
1545                 return (E_OUTOFMEMORY);
1546             }
1547
1548             // Get the memory for the array that the hash table is going to use
1549             pData->arrHash = new (nothrow) CLASSHASHENTRY[HASH_ARRAY_SIZE_INITIAL];
1550             if (pData->arrHash == NULL)
1551             {
1552                 delete pData->pHashTable;
1553                 delete pData;
1554                 return (E_OUTOFMEMORY);
1555             }
1556
1557             // Save the number of elements in the array
1558             pData->cHash = HASH_ARRAY_SIZE_INITIAL;
1559
1560             // Now initialize the hash table
1561             HRESULT hr = pData->pHashTable->NewInit((BYTE *)pData->arrHash, sizeof(CLASSHASHENTRY));
1562             if (hr == E_OUTOFMEMORY)
1563             {
1564                 delete [] pData->arrHash;
1565                 delete pData->pHashTable;
1566                 delete pData;
1567                 return (E_OUTOFMEMORY);
1568             }
1569             _ASSERTE(pData->pHashTable->IsInited());
1570
1571             // Null some entries
1572             pData->arrClsId = NULL;
1573             pData->arrcObjects = NULL;
1574             pData->cLength = 0;
1575
1576             // Hold on to the structure
1577             m_pSavedAllocDataBlock = pData;
1578         }
1579
1580         // Got some memory and hash table to store entries, yay!
1581         *((size_t *)pHeapId) = (size_t)pData;
1582
1583         // Initialize the data
1584         pData->iHash = 0;
1585         pData->pHashTable->Clear();
1586     }
1587
1588     _ASSERTE(pData->iHash <= pData->cHash);
1589     _ASSERTE(dwProcId == GetCurrentProcessId());
1590
1591     // Lookup to see if this class already has an entry
1592     CLASSHASHENTRY * pEntry = 
1593         reinterpret_cast<CLASSHASHENTRY *>(pData->pHashTable->Find(HASH(clsId), (SIZE_T)clsId));
1594
1595     // If this class has already been encountered, just increment the counter.
1596     if (pEntry)
1597         pEntry->m_count++;
1598
1599     // Otherwise, need to add this one as a new entry in the hash table
1600     else
1601     {
1602         // If we're full, we need to realloc
1603         if (pData->iHash == pData->cHash)
1604         {
1605             // Try to realloc the memory
1606             CLASSHASHENTRY     *tmp = new (nothrow) CLASSHASHENTRY[pData->cHash + HASH_ARRAY_SIZE_INC];
1607             if (!tmp)
1608             {
1609                 return (E_OUTOFMEMORY);
1610             }
1611
1612             _ASSERTE(pData->arrHash);
1613             memcpy (tmp, pData->arrHash, pData->cHash*sizeof(CLASSHASHENTRY));
1614             delete [] pData->arrHash;
1615             pData->arrHash = tmp;
1616             // Tell the hash table that the memory location of the array has changed
1617             pData->pHashTable->SetTable((BYTE *)pData->arrHash);
1618
1619             // Save the new size of the array
1620             pData->cHash += HASH_ARRAY_SIZE_INC;
1621         }
1622
1623         // Now add the new entry
1624         CLASSHASHENTRY *pNewEntry = (CLASSHASHENTRY *) pData->pHashTable->Add(HASH(clsId), pData->iHash++);
1625
1626         pNewEntry->m_clsId = clsId;
1627         pNewEntry->m_count = 1;
1628     }
1629
1630     // Indicate success
1631     return (S_OK);
1632 }
1633
1634 HRESULT EEToProfInterfaceImpl::EndAllocByClass(void *pHeapId)
1635 {
1636     _ASSERTE(pHeapId != NULL);
1637     _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1638
1639     HRESULT hr = S_OK;
1640
1641     AllocByClassData *pData = (AllocByClassData *)(*((size_t *)pHeapId));
1642
1643     // Notify the profiler if there are elements to notify it of
1644     if (pData != NULL)
1645         hr = NotifyAllocByClass(pData);
1646
1647 #ifdef _DEBUG
1648     (*((size_t *)pHeapId)) = (size_t)(-1);
1649 #endif // _DEBUG
1650
1651     return (hr);
1652 }
1653
1654 //---------------------------------------------------------------------------------------
1655 //
1656 // Convert ETW-style root flag bitmask to ProfAPI-stye root flag bitmask
1657 //
1658 // Arguments:
1659 //      dwEtwRootFlags - ETW-style root flag bitmask
1660 //
1661 // Return Value:
1662 //      The corresponding ProfAPI-stye root flag bitmask
1663 //
1664
1665 DWORD EtwRootFlagsToProfApiRootFlags(DWORD dwEtwRootFlags)
1666 {
1667     LIMITED_METHOD_CONTRACT;
1668
1669     // If a new ETW flag is added, adjust this assert, and add a case below.
1670     _ASSERTE((dwEtwRootFlags & 
1671         ~(kEtwGCRootFlagsPinning | kEtwGCRootFlagsWeakRef | kEtwGCRootFlagsInterior | kEtwGCRootFlagsRefCounted))
1672                     == 0);
1673
1674     DWORD dwProfApiRootFlags = 0;
1675
1676     if ((dwEtwRootFlags & kEtwGCRootFlagsPinning) != 0)
1677     {
1678         dwProfApiRootFlags |= COR_PRF_GC_ROOT_PINNING;
1679     }
1680     if ((dwEtwRootFlags & kEtwGCRootFlagsWeakRef) != 0)
1681     {
1682         dwProfApiRootFlags |= COR_PRF_GC_ROOT_WEAKREF;
1683     }
1684     if ((dwEtwRootFlags & kEtwGCRootFlagsInterior) != 0)
1685     {
1686         dwProfApiRootFlags |= COR_PRF_GC_ROOT_INTERIOR;
1687     }
1688     if ((dwEtwRootFlags & kEtwGCRootFlagsRefCounted) != 0)
1689     {
1690         dwProfApiRootFlags |= COR_PRF_GC_ROOT_REFCOUNTED;
1691     }
1692     return dwProfApiRootFlags;
1693 }
1694
1695 //---------------------------------------------------------------------------------------
1696 //
1697 // Convert ETW-style root kind enum to ProfAPI-stye root kind enum
1698 //
1699 // Arguments:
1700 //      dwEtwRootKind - ETW-style root kind enum
1701 //
1702 // Return Value:
1703 //      Corresponding ProfAPI-stye root kind enum
1704 //
1705
1706 DWORD EtwRootKindToProfApiRootKind(EtwGCRootKind dwEtwRootKind)
1707 {
1708     LIMITED_METHOD_CONTRACT;
1709     
1710     switch(dwEtwRootKind)
1711     {
1712     default:
1713         // If a new ETW root kind is added, create a profapi root kind as well, and add
1714         // the appropriate case below
1715         _ASSERTE(!"Unrecognized ETW root kind");
1716         // Deliberately fall through to kEtwGCRootKindOther
1717
1718     case kEtwGCRootKindOther:
1719         return COR_PRF_GC_ROOT_OTHER;
1720
1721     case  kEtwGCRootKindStack:
1722         return COR_PRF_GC_ROOT_STACK;
1723
1724     case kEtwGCRootKindFinalizer:
1725         return COR_PRF_GC_ROOT_FINALIZER;
1726
1727     case kEtwGCRootKindHandle:
1728         return COR_PRF_GC_ROOT_HANDLE;
1729     }
1730 }
1731
1732 //---------------------------------------------------------------------------------------
1733 //
1734 // Callback used by the GC when scanning the roots (via ScanRootsHelper in
1735 // ProfToEEInterfaceImpl.cpp).
1736 //
1737 // Arguments:
1738 //      objectId - Root object reference encountered
1739 //      dwEtwRootKind - ETW enum describing what kind of root objectId is
1740 //      dwEtwRootFlags - ETW flags describing the root qualities of objectId
1741 //      rootID - Root's methoddesc if dwEtwRootKind==kEtwGCRootKindStack, else NULL
1742 //      pHeapId - Used as a GCReferencesData * to keep track of the GC references
1743 //
1744 // Return Value:
1745 //      HRESULT indicating success or failure.
1746 //
1747
1748 HRESULT EEToProfInterfaceImpl::RootReference2(BYTE * objectId,
1749                                               EtwGCRootKind dwEtwRootKind,
1750                                               EtwGCRootFlags dwEtwRootFlags,
1751                                               void * rootID, 
1752                                               void * pHeapId)
1753 {
1754     _ASSERTE(pHeapId);
1755     _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1756
1757     LOG((LF_CORPROF, LL_INFO100000, "**PROF: Root Reference. "
1758             "ObjectID:0x%p dwEtwRootKind:0x%x dwEtwRootFlags:0x%x rootId:0x%p HeadId:0x%p\n",
1759             objectId, dwEtwRootKind, dwEtwRootFlags, rootID, pHeapId));
1760
1761     DWORD dwProfApiRootFlags = EtwRootFlagsToProfApiRootFlags(dwEtwRootFlags);
1762     DWORD dwProfApiRootKind = EtwRootKindToProfApiRootKind((EtwGCRootKind) dwEtwRootKind);
1763
1764     // Get a pointer to the data for this heap
1765     GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1766
1767     // If this is the first notification of an extended root reference for this heap
1768     // in this particular gc activation, then we need to get a ref data block
1769     // from the free list of blocks, or if that's empty then we need to
1770     // allocate a new one.
1771     if (pData == NULL)
1772     {
1773         pData = AllocateMovedReferencesData();
1774         if (pData == NULL)
1775             return (E_OUTOFMEMORY);
1776
1777         // Set the cookie so that we will be provided it on subsequent
1778         // callbacks
1779         ((*((size_t *)pHeapId))) = (size_t)pData;
1780     }
1781
1782     _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1783
1784     // If the struct has been filled, then we need to notify the profiler of
1785     // these root references and clear the struct for the next load of
1786     // root references
1787     if (pData->curIdx == kcReferencesMax)
1788     {
1789         RootReferences2(pData);
1790         pData->curIdx = 0;
1791     }
1792
1793     // Now save the information in the struct
1794     pData->arrpbMemBlockStartOld[pData->curIdx] = objectId;
1795     pData->arrpbMemBlockStartNew[pData->curIdx] = (BYTE *)rootID;
1796
1797     // assert that dwProfApiRootKind and dwProfApiRootFlags both fit in 16 bits, so we can
1798     // pack both into a 32-bit word
1799     _ASSERTE((dwProfApiRootKind & 0xffff) == dwProfApiRootKind && (dwProfApiRootFlags & 0xffff) == dwProfApiRootFlags);
1800
1801     pData->arrULONG[pData->curIdx] = (dwProfApiRootKind << 16) | dwProfApiRootFlags;
1802
1803     // Increment the index into the parallel arrays
1804     pData->curIdx += 1;
1805
1806     return S_OK;
1807 }
1808
1809 //---------------------------------------------------------------------------------------
1810 //
1811 // Called by the GC to indicate that the GC is finished calling
1812 // EEToProfInterfaceImpl::RootReference2 for this collection.  This function will
1813 // call into the profiler to notify it of all the root references we've cached.
1814 //
1815 // Arguments:
1816 //      pHeapId - Casted to a GCReferencesData * that contains the root references
1817 //                we've cached.
1818 //
1819 // Return Value:
1820 //      HRESULT indicating success or failure.
1821 //
1822
1823 HRESULT EEToProfInterfaceImpl::EndRootReferences2(void * pHeapId)
1824 {
1825     _ASSERTE(pHeapId);
1826     _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1827
1828     HRESULT hr = S_OK;
1829
1830     // Get a pointer to the data for this heap
1831     GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1832
1833     // If there were no moved references, profiler doesn't need to know
1834     if (!pData)
1835         return (S_OK);
1836
1837     // Communicate the moved references to the profiler
1838     _ASSERTE(pData->curIdx> 0);
1839     hr = RootReferences2(pData);
1840
1841     // Now we're done with the data block, we can shove it onto the free list
1842     FreeMovedReferencesData(pData);
1843
1844 #ifdef _DEBUG
1845     // Set the cookie to an invalid number
1846     (*((size_t *)pHeapId)) = (size_t)(-1);
1847 #endif // _DEBUG
1848
1849     return (hr);
1850 }
1851
1852 //---------------------------------------------------------------------------------------
1853 //
1854 // Callback used by the GC when scanning the roots (via 
1855 // Ref_ScanDependentHandlesForProfilerAndETW in ObjectHandle.cpp).
1856 //
1857 // Arguments:
1858 //      primaryObjectId   - Primary object reference in the DependentHandle
1859 //      secondaryObjectId - Secondary object reference in the DependentHandle
1860 //      rootID            - The DependentHandle maintaining the dependency relationship
1861 //      pHeapId           - Used as a GCReferencesData * to keep track of the GC references
1862 //
1863 // Return Value:
1864 //      HRESULT indicating success or failure.
1865 //
1866
1867 HRESULT EEToProfInterfaceImpl::ConditionalWeakTableElementReference(BYTE * primaryObjectId,
1868                         BYTE * secondaryObjectId, 
1869                         void * rootID, 
1870                         void * pHeapId)
1871 {
1872     _ASSERTE(pHeapId);
1873     _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1874
1875     // Callers must ensure the profiler asked to be notified about dependent handles,
1876     // since this is only available for profilers implementing ICorProfilerCallback5 and
1877     // greater.
1878     _ASSERTE(CORProfilerTrackConditionalWeakTableElements());
1879
1880     LOG((LF_CORPROF, LL_INFO100000, "**PROF: Root Dependent Handle. "
1881             "PrimaryObjectID:0x%p SecondaryObjectID:0x%p rootId:0x%p HeadId:0x%p\n",
1882             primaryObjectId, secondaryObjectId, rootID, pHeapId));
1883
1884     // Get a pointer to the data for this heap
1885     GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1886
1887     // If this is the first notification of a dependent handle reference in
1888     // this particular gc activation, then we need to get a ref data block
1889     // from the free list of blocks, or if that's empty then we need to
1890     // allocate a new one.
1891     if (pData == NULL)
1892     {
1893         pData = AllocateMovedReferencesData();
1894         if (pData == NULL)
1895             return (E_OUTOFMEMORY);
1896
1897         // Set the cookie so that we will be provided it on subsequent
1898         // callbacks
1899         ((*((size_t *)pHeapId))) = (size_t)pData;
1900     }
1901
1902     _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1903
1904     // If the struct has been filled, then we need to notify the profiler of
1905     // these dependent handle references and clear the struct for the next 
1906     // load of dependent handle references
1907     if (pData->curIdx == kcReferencesMax)
1908     {
1909         ConditionalWeakTableElementReferences(pData);
1910         pData->curIdx = 0;
1911     }
1912
1913     // Now save the information in the struct
1914     pData->arrpbMemBlockStartOld[pData->curIdx] = primaryObjectId;
1915     pData->arrpbMemBlockStartNew[pData->curIdx] = secondaryObjectId;
1916     pData->arrpbRootId[pData->curIdx]           = (BYTE*) rootID;
1917
1918     // Increment the index into the parallel arrays
1919     pData->curIdx += 1;
1920
1921     return S_OK;
1922 }
1923
1924 //---------------------------------------------------------------------------------------
1925 //
1926 // Called by the GC to indicate that the GC is finished calling
1927 // EEToProfInterfaceImpl::ConditionalWeakTableElementReference for this collection.  This 
1928 // function will call into the profiler to notify it of all the DependentHandle references
1929 // we've cached.
1930 //
1931 // Arguments:
1932 //      pHeapId - Casted to a GCReferencesData * that contains the dependent handle 
1933 //                references we've cached.
1934 //
1935 // Return Value:
1936 //      HRESULT indicating success or failure.
1937 //
1938
1939 HRESULT EEToProfInterfaceImpl::EndConditionalWeakTableElementReferences(void * pHeapId)
1940 {
1941     _ASSERTE(pHeapId);
1942     _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1943
1944     // Callers must ensure the profiler asked to be notified about dependent handles,
1945     // since this is only available for profilers implementing ICorProfilerCallback5 and
1946     // greater.
1947     _ASSERTE(CORProfilerTrackConditionalWeakTableElements());
1948
1949     HRESULT hr = S_OK;
1950
1951     // Get a pointer to the data for this heap
1952     GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1953
1954     // If there were no dependent handles, profiler doesn't need to know
1955     if (!pData)
1956         return (S_OK);
1957
1958     // Communicate the dependent handle references to the profiler
1959     _ASSERTE(pData->curIdx > 0);
1960     hr = ConditionalWeakTableElementReferences(pData);
1961
1962     // Now we're done with the data block, we can shove it onto the free list
1963     FreeMovedReferencesData(pData);
1964
1965 #ifdef _DEBUG
1966     // Set the cookie to an invalid number
1967     (*((size_t *)pHeapId)) = (size_t)(-1);
1968 #endif // _DEBUG
1969
1970     return (hr);
1971 }
1972
1973
1974
1975 //---------------------------------------------------------------------------------------
1976 //
1977 // Returns whether the profiler performed unrevertible acts, such as instrumenting
1978 // code or requesting ELT hooks.  RequestProfilerDetach uses this function before
1979 // performing any sealing or evacuation checks to determine whether it's even possible
1980 // for the profiler ever to detach.
1981 //
1982 // Return Value:
1983 //    * S_OK if it's safe to attempt a detach.  Evacuation checks must still be performed
1984 //        before actually unloading the profiler.
1985 //    * else, an HRESULT error value indicating what the profiler did that made it
1986 //        undetachable.  This is a public HRESULT suitable for returning from the
1987 //        RequestProfilerDetach API.
1988 //
1989
1990 HRESULT EEToProfInterfaceImpl::EnsureProfilerDetachable()
1991 {
1992     LIMITED_METHOD_CONTRACT;
1993
1994     if (((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE) != 0) ||
1995         ((g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) != 0))
1996     {
1997         LOG((
1998             LF_CORPROF, 
1999             LL_ERROR, 
2000             "**PROF: Profiler may not detach because it set an immutable flag.  Flags = 0x%x.\n", 
2001             g_profControlBlock.dwEventMask));
2002
2003         return CORPROF_E_IMMUTABLE_FLAGS_SET;
2004     }
2005
2006     if ((m_pEnter != NULL)             || 
2007         (m_pLeave != NULL)             || 
2008         (m_pTailcall != NULL)          ||
2009         (m_pEnter2 != NULL)            || 
2010         (m_pLeave2 != NULL)            || 
2011         (m_pTailcall2 != NULL)         ||
2012         (m_pEnter3 != NULL)            || 
2013         (m_pEnter3WithInfo != NULL)    || 
2014         (m_pLeave3 != NULL)            || 
2015         (m_pLeave3WithInfo != NULL)    || 
2016         (m_pTailcall3 != NULL)         ||
2017         (m_pTailcall3WithInfo != NULL))
2018     {
2019         LOG((
2020             LF_CORPROF, 
2021             LL_ERROR, 
2022             "**PROF: Profiler may not detach because it set an ELT(2) hook.\n"));
2023
2024         return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;
2025     }
2026
2027     if (m_fUnrevertiblyModifiedIL)
2028     {
2029         LOG((
2030             LF_CORPROF, 
2031             LL_ERROR, 
2032             "**PROF: Profiler may not detach because it called SetILFunctionBody.\n"));
2033
2034         return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;
2035     }
2036
2037     if (m_fModifiedRejitState)
2038     {
2039         LOG((
2040             LF_CORPROF, 
2041             LL_ERROR, 
2042             "**PROF: Profiler may not detach because it enabled Rejit.\n"));
2043
2044         return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;   
2045     }
2046
2047     return S_OK;
2048 }
2049
2050 // Declarations for asm wrappers of profiler callbacks
2051 EXTERN_C void STDMETHODCALLTYPE ProfileEnterNaked(FunctionIDOrClientID functionIDOrClientID);
2052 EXTERN_C void STDMETHODCALLTYPE ProfileLeaveNaked(FunctionIDOrClientID functionIDOrClientID);
2053 EXTERN_C void STDMETHODCALLTYPE ProfileTailcallNaked(FunctionIDOrClientID functionIDOrClientID);
2054 #define PROFILECALLBACK(name) name##Naked
2055
2056 //---------------------------------------------------------------------------------------
2057 //
2058 // Determines the hooks (slow path vs. fast path) to which the JIT shall
2059 // insert calls, and then tells the JIT which ones we want
2060 //
2061 // Return Value:
2062 //      HRESULT indicating success or failure
2063 //
2064
2065 HRESULT EEToProfInterfaceImpl::DetermineAndSetEnterLeaveFunctionHooksForJit()
2066 {
2067     CONTRACTL
2068     {
2069         NOTHROW;
2070         GC_NOTRIGGER;
2071         MODE_ANY;
2072         CANNOT_TAKE_LOCK;
2073     }
2074     CONTRACTL_END;
2075
2076     // We're doing all ELT3 hooks, all-Whidbey hooks or all-Everett hooks.  No mixing and matching.
2077     BOOL fCLRv4Hooks = (m_pEnter3 != NULL)             ||
2078                        (m_pLeave3 != NULL)             ||
2079                        (m_pTailcall3 != NULL)          ||
2080                        (m_pEnter3WithInfo != NULL)     ||
2081                        (m_pLeave3WithInfo != NULL)     ||
2082                        (m_pTailcall3WithInfo != NULL);
2083
2084     BOOL fWhidbeyHooks = (m_pEnter2 != NULL)     ||
2085                          (m_pLeave2 != NULL)     ||
2086                          (m_pTailcall2 != NULL);
2087
2088     // If no hooks were set (e.g., SetEventMask called with COR_PRF_MONITOR_ENTERLEAVE, 
2089     // but SetEnterLeaveFunctionHooks(*) never called), then nothing to do
2090     if (!fCLRv4Hooks           &&
2091         !fWhidbeyHooks         &&
2092         (m_pEnter == NULL)     &&
2093         (m_pLeave == NULL)     &&
2094         (m_pTailcall == NULL))
2095     {
2096         return S_OK;
2097     }
2098
2099
2100     HRESULT hr = S_OK;
2101     
2102     EX_TRY
2103     {
2104         if (fCLRv4Hooks)
2105         {
2106             // For each type of hook (enter/leave/tailcall) we must determine if we can use the
2107             // happy lucky fast path (i.e., direct call from JITd code right into the profiler's
2108             // hook or the JIT default stub (see below)), or the slow path (i.e., call into an 
2109             // intermediary FCALL which then calls the profiler's hook) with extra information
2110             // about the current function.
2111
2112             hr = SetEnterLeaveFunctionHooksForJit(
2113                 (m_pEnter3WithInfo != NULL) ?
2114                     PROFILECALLBACK(ProfileEnter) :
2115                     m_pEnter3,
2116                 (m_pLeave3WithInfo != NULL) ?
2117                     PROFILECALLBACK(ProfileLeave) :
2118                     m_pLeave3,
2119                 (m_pTailcall3WithInfo != NULL) ?
2120                     PROFILECALLBACK(ProfileTailcall) :
2121                     m_pTailcall3);
2122         }
2123         else
2124         {
2125             //
2126             // Everett or Whidbey hooks.
2127             // 
2128
2129             // When using Everett or Whidbey hooks, the check looks like this:
2130             //
2131             // IF       Hook exists
2132             // THEN     Use slow path
2133             //
2134             // Why?
2135             //
2136             // - If the profiler wants the old-style Whidbey or Everett hooks, we need a wrapper 
2137             // to convert from the ELT3 prototype the JIT expects to the Whidbey or Everett 
2138             // prototype the profiler expects. It applies to Whidbey fast-path hooks.   And due 
2139             // to the overhead of looking up FunctionID from cache and using lock to synchronize 
2140             // cache accesses, the so-called Whidbey fast-path hooks are much slower than they 
2141             // used to be.  Whidbey and Everett hooks are supported to keep existing profiler
2142             // running, but the profiler writers are encouraged to use ELT3 interface for the 
2143             // best performance.
2144             //
2145             // Implicit in the above logic is if one of the hook types has no hook pointer 
2146             // specified, then we pass NULL as the hook pointer to the JIT, in which case the JIT
2147             // just generates a call to the default stub (a single ret) w/out invoking the slow-path
2148             // wrapper.  I call this the "fast path to nowhere"
2149
2150             BOOL fEnter = (m_pEnter != NULL) || (m_pEnter2 != NULL);
2151             BOOL fLeave = (m_pLeave != NULL) || (m_pLeave2 != NULL);
2152             BOOL fTailcall = (m_pTailcall != NULL) || (m_pTailcall2 != NULL);
2153
2154             hr = SetEnterLeaveFunctionHooksForJit(
2155                 fEnter ?
2156                     PROFILECALLBACK(ProfileEnter) :
2157                     NULL,
2158                 fLeave ?
2159                     PROFILECALLBACK(ProfileLeave) :
2160                     NULL,
2161                 fTailcall ?
2162                     PROFILECALLBACK(ProfileTailcall) :
2163                     NULL);
2164         }
2165     }
2166     EX_CATCH
2167     {
2168         hr = E_FAIL;
2169     }
2170     // We need to swallow all exceptions, because we will lock otherwise (in addition to
2171     // the IA64-only lock while allocating stub space!).  For example, specifying
2172     // RethrowTerminalExceptions forces us to test to see if the caught exception is
2173     // terminal and Exception::IsTerminal() can lock if we get a handle table cache miss
2174     // while getting a handle for the exception.  It is good to minimize locks from 
2175     // profiler Info functions (and their callees), and this is a dumb lock to have,
2176     // given that we can avoid it altogether by just having terminal exceptions be
2177     // swallowed here, and returning the failure to the profiler.  For those who don't
2178     // like swallowing terminal exceptions, this is mitigated by the fact that,
2179     // currently, an exception only gets thrown from SetEnterLeaveFunctionHooksForJit on
2180     // IA64.  But to keep consistent (and in case the world changes), we'll do this on
2181     // all platforms.
2182     EX_END_CATCH(SwallowAllExceptions);
2183
2184     return hr;
2185 }
2186
2187
2188 //---------------------------------------------------------------------------------------
2189 //
2190 // The Info method SetEventMask() simply defers to this function to do the real work.
2191 //
2192 // Arguments:
2193 //      dwEventMask - Event mask specified by the profiler
2194 //
2195 // Return Value:
2196 //     HRESULT indicating success / failure to return straight through to the profiler
2197 //
2198
2199 HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMaskHigh)
2200 {
2201     CONTRACTL
2202     {
2203         NOTHROW;
2204         GC_NOTRIGGER;
2205         MODE_ANY;
2206         EE_THREAD_NOT_REQUIRED;
2207         CANNOT_TAKE_LOCK;
2208     }
2209     CONTRACTL_END;
2210
2211     static const DWORD kEventFlagsRequiringSlowPathEnterLeaveHooks =
2212         COR_PRF_ENABLE_FUNCTION_ARGS   |
2213         COR_PRF_ENABLE_FUNCTION_RETVAL |
2214         COR_PRF_ENABLE_FRAME_INFO
2215         ;
2216
2217     static const DWORD kEventFlagsAffectingEnterLeaveHooks =
2218         COR_PRF_MONITOR_ENTERLEAVE     |
2219         kEventFlagsRequiringSlowPathEnterLeaveHooks
2220         ;
2221
2222     HRESULT hr;
2223
2224 #ifdef _DEBUG
2225     // Some tests need to enable immutable flags after startup, when a profiler is
2226     // attached. These flags enable features that are used solely to verify the
2227     // correctness of other, MUTABLE features. Examples: enable immutable ELT to create
2228     // shadow stacks to verify stack walks (which can be done mutably via manual
2229     // EBP-frame walking), or enable immutable DSS to gather IP addresses to verify the
2230     // mutable GetFunctionFromIP.
2231     // 
2232     // Similarly, test profilers may need to extend the set of flags allowable on attach
2233     // to enable features that help verify other parts of the profapi that ARE allowed
2234     // on attach.
2235     // 
2236     // See code:#P2CLRRestrictionsOverview for more information
2237     DWORD dwImmutableEventFlags = COR_PRF_MONITOR_IMMUTABLE;
2238     DWORD dwAllowableAfterAttachEventFlags = COR_PRF_ALLOWABLE_AFTER_ATTACH;
2239     DWORD dwTestOnlyAllowedEventMask = 0;
2240     dwTestOnlyAllowedEventMask = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TestOnlyAllowedEventMask);
2241     if (dwTestOnlyAllowedEventMask != 0)
2242     {
2243         // Remove from the immutable flag list those flags that a test-only profiler may
2244         // need to set post-startup (specified via COMPlus_TestOnlyAllowedEventMask)
2245         dwImmutableEventFlags &= ~dwTestOnlyAllowedEventMask;  
2246
2247         // And add to the "allowable after attach" list the same test-only flags.
2248         dwAllowableAfterAttachEventFlags |= dwTestOnlyAllowedEventMask;
2249         
2250         LOG((LF_CORPROF, LL_INFO10, "**PROF: TestOnlyAllowedEventMask=0x%x. New immutable flags=0x%x.  New AllowableAfterAttach flags=0x%x\n", 
2251             dwTestOnlyAllowedEventMask, 
2252             dwImmutableEventFlags,
2253             dwAllowableAfterAttachEventFlags));
2254     }
2255 #endif //_DEBUG
2256
2257     // If we're not in initialization or shutdown, make sure profiler is
2258     // not trying to set an immutable attribute
2259     // FUTURE: If we add immutable flags to the high event mask, this would be a good
2260     // place to check for them as well.
2261     if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
2262     {
2263 #ifdef _DEBUG
2264         if (((dwEventMask & dwImmutableEventFlags) !=
2265                 (g_profControlBlock.dwEventMask & dwImmutableEventFlags)) ||
2266 #else //!_DEBUG
2267         if (((dwEventMask & COR_PRF_MONITOR_IMMUTABLE) !=
2268                 (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE)) ||
2269 #endif //_DEBUG
2270             ((dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) !=
2271                 (g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE)))
2272         {
2273             // FUTURE: Should we have a dedicated HRESULT for setting immutable flag?
2274             return E_FAIL;
2275         }
2276     }
2277
2278     // If this is an attaching profiler, make sure the profiler only sets flags
2279     // allowable after an attach
2280     if (m_fLoadedViaAttach &&
2281 #ifdef _DEBUG
2282         (((dwEventMask & (~dwAllowableAfterAttachEventFlags)) != 0) ||
2283 #else //!_DEBUG
2284         (((dwEventMask & (~COR_PRF_ALLOWABLE_AFTER_ATTACH)) != 0) ||
2285 #endif //_DEBUG
2286         (dwEventMaskHigh & (~COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH))))
2287     {
2288         return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER;
2289     }
2290
2291     // After fast path ELT hooks are set in Initial callback, the startup profiler is not allowed to change flags 
2292     // that require slow path ELT hooks or disable ELT hooks.
2293     if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) && 
2294         (
2295             (m_pEnter3    != NULL) || 
2296             (m_pLeave3    != NULL) || 
2297             (m_pTailcall3 != NULL)
2298         ) &&
2299         (
2300             ((dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0) ||
2301             ((dwEventMask & COR_PRF_MONITOR_ENTERLEAVE) == 0)
2302         )
2303        )
2304     {
2305         _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0);
2306         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2307     }
2308
2309     // After slow path ELT hooks are set in Initial callback, the startup profiler is not allowed to remove
2310     // all flags that require slow path ELT hooks or to change the flag to disable the ELT hooks.
2311     if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) && 
2312         (
2313             (m_pEnter3WithInfo    != NULL) ||
2314             (m_pLeave3WithInfo    != NULL) ||
2315             (m_pTailcall3WithInfo != NULL)
2316         ) &&
2317         (
2318             ((dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0) ||
2319             ((dwEventMask & COR_PRF_MONITOR_ENTERLEAVE) == 0)
2320         )
2321        )
2322     {
2323         _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0);
2324         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2325     }
2326
2327
2328     // Note whether the caller is changing flags that affect enter leave hooks
2329     BOOL fEnterLeaveHooksAffected = 
2330         // Did any of the relevant flags change?
2331         (
2332             (
2333                 // Old flags
2334                 ((g_profControlBlock.dwEventMask & kEventFlagsAffectingEnterLeaveHooks) ^
2335                 // XORed w/ the new flags
2336                 (dwEventMask & kEventFlagsAffectingEnterLeaveHooks))
2337             ) != 0
2338         ) &&
2339         // And are any enter/leave hooks set?
2340         (
2341             (m_pEnter3            != NULL) ||
2342             (m_pEnter3WithInfo    != NULL) ||
2343             (m_pEnter2            != NULL) ||
2344             (m_pEnter             != NULL) ||
2345             (m_pLeave3            != NULL) ||
2346             (m_pLeave3WithInfo    != NULL) ||
2347             (m_pLeave2            != NULL) ||
2348             (m_pLeave             != NULL) ||
2349             (m_pTailcall3         != NULL) ||
2350             (m_pTailcall3WithInfo != NULL) ||
2351             (m_pTailcall2         != NULL) ||
2352             (m_pTailcall          != NULL)
2353         );
2354
2355     BOOL fNeedToTurnOffConcurrentGC = FALSE;
2356
2357     if (((dwEventMask & COR_PRF_MONITOR_GC) != 0) && 
2358         ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_GC) == 0))
2359     {
2360         // We don't need to worry about startup load as we'll turn off concurrent GC later
2361         if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
2362         {        
2363             // Since we're not an initializing startup profiler, the EE must be fully started up
2364             // so we can check whether concurrent GC is on
2365             if (!g_fEEStarted)
2366             {
2367                 return CORPROF_E_RUNTIME_UNINITIALIZED;
2368             }
2369             
2370             // We don't want to change the flag before GC is fully initialized, 
2371             // otherwise the concurrent GC setting would be overwritten
2372             // Make sure GC is fully initialized before proceed 
2373             if (!IsGarbageCollectorFullyInitialized())
2374             {
2375                 return CORPROF_E_NOT_YET_AVAILABLE;
2376             }
2377
2378             // If we are attaching and we are turning on COR_PRF_MONITOR_GC, turn off concurrent GC later
2379             // in this function
2380             if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForAttachLoad)
2381             {
2382                 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled())
2383                 {
2384                     // We only allow turning off concurrent GC in the profiler attach thread inside
2385                     // InitializeForAttach, otherwise we would be vulnerable to weird races such as 
2386                     // SetEventMask running on a separate thread and trying to turn off concurrent GC.
2387                     // The best option here is to fail with CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE.
2388                     // Existing Dev10 profilers should be prepared to handle such case.
2389                     if (IsProfilerAttachThread())
2390                     {
2391                         fNeedToTurnOffConcurrentGC = TRUE;
2392                     }
2393                     else
2394                     {
2395                         return CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE;
2396                     }
2397                 }
2398             }
2399             else
2400             {
2401                 // Fail if concurrent GC is enabled
2402                 // This should only happen for attach profilers if user didn't turn on COR_PRF_MONITOR_GC 
2403                 // at attach time
2404                 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled())
2405                 {
2406                     return CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE;
2407                 }        
2408             }
2409         }        
2410     }
2411
2412     if ((dwEventMask & COR_PRF_ENABLE_REJIT) != 0)
2413     {
2414         if ((g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad) && !ReJitManager::IsReJITEnabled())
2415         {
2416             return CORPROF_E_REJIT_NOT_ENABLED;
2417         }
2418
2419         g_profControlBlock.pProfInterface->SetModifiedRejitState();
2420     }
2421
2422     // High event bits
2423
2424     if (((dwEventMaskHigh & COR_PRF_HIGH_ADD_ASSEMBLY_REFERENCES) != 0) &&
2425         !IsCallback6Supported())
2426     {
2427         return CORPROF_E_CALLBACK6_REQUIRED;
2428     }
2429
2430     if (((dwEventMaskHigh & COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED) != 0) &&
2431         !IsCallback7Supported())
2432     {
2433         return CORPROF_E_CALLBACK7_REQUIRED;
2434     }
2435
2436     // Now save the modified masks
2437     g_profControlBlock.dwEventMask = dwEventMask;
2438     g_profControlBlock.dwEventMaskHigh = dwEventMaskHigh;
2439
2440     if (fEnterLeaveHooksAffected)
2441     {
2442         hr = DetermineAndSetEnterLeaveFunctionHooksForJit();
2443         if (FAILED(hr))
2444         {
2445             return hr;
2446         }
2447     }
2448
2449     if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad)
2450     {
2451         // If the profiler has requested remoting cookies so that it can
2452         // track logical call stacks, then we must initialize the cookie
2453         // template.
2454         if ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_REMOTING_COOKIE)
2455             == COR_PRF_MONITOR_REMOTING_COOKIE)
2456         {
2457             hr = InitGUID();
2458             if (FAILED(hr))
2459             {
2460                 return hr;
2461             }
2462         }
2463     }
2464
2465     // Turn off concurrent GC as the last step so that we don't need to turn it back on if something
2466     // else failed after that
2467     if (fNeedToTurnOffConcurrentGC)
2468     {
2469         // Turn off concurrent GC if it is on so that user can walk the heap safely in GC callbacks
2470         IGCHeap * pGCHeap = GCHeapUtilities::GetGCHeap();
2471         
2472         LOG((LF_CORPROF, LL_INFO10, "**PROF: Turning off concurrent GC at attach.\n"));
2473         
2474         // First turn off concurrent GC
2475         pGCHeap->TemporaryDisableConcurrentGC();
2476
2477         //
2478         // Then wait until concurrent GC to finish if concurrent GC is in progress
2479         // User can use a timeout that can be set by environment variable if the GC turns out
2480         // to be too long. The default value is INFINITE.
2481         //
2482         // NOTE: 
2483         // If we don't do it in this order there might be a new concurrent GC started 
2484         // before we actually turn off concurrent GC
2485         //                
2486         hr = pGCHeap->WaitUntilConcurrentGCCompleteAsync(m_dwConcurrentGCWaitTimeoutInMs);
2487         if (FAILED(hr))
2488         {
2489             if (hr == HRESULT_FROM_WIN32(ERROR_TIMEOUT))
2490             {
2491                 // Convert it to a more specific HRESULT
2492                 hr = CORPROF_E_TIMEOUT_WAITING_FOR_CONCURRENT_GC;
2493
2494                 // Since we cannot call LogProfEvent here due to contact violations, we'll need to
2495                 // remember the fact that we've failed, and report the failure later after InitializeForAttach
2496                 m_bHasTimedOutWaitingForConcurrentGC = TRUE;
2497             }
2498             
2499             pGCHeap->TemporaryEnableConcurrentGC();
2500             return hr;
2501         }
2502     
2503         // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling
2504         g_profControlBlock.fConcurrentGCDisabledForAttach = TRUE;
2505     
2506         LOG((LF_CORPROF, LL_INFO10, "**PROF: Concurrent GC has been turned off at attach.\n"));
2507     }
2508
2509     // Return success
2510     return S_OK;
2511 }
2512
2513 //---------------------------------------------------------------------------------------
2514 //
2515 // The Info method SetEnterLeaveFunctionHooks() simply defers to this function to do the
2516 // real work.
2517 //
2518 // Arguments:
2519 //     (same as specified in the public API docs)
2520 //
2521 // Return Value:
2522 //     HRESULT indicating success / failure to return straight through to the profiler
2523 //
2524
2525 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncEnter,
2526                                                           FunctionLeave * pFuncLeave,
2527                                                           FunctionTailcall * pFuncTailcall)
2528 {
2529     CONTRACTL
2530     {
2531         NOTHROW;
2532         GC_NOTRIGGER;
2533         MODE_ANY;
2534         EE_THREAD_NOT_REQUIRED;
2535         CANNOT_TAKE_LOCK;
2536     }
2537     CONTRACTL_END;
2538
2539     // You have to be setting at least one hook
2540     if ((pFuncEnter == NULL) && (pFuncLeave == NULL) && (pFuncTailcall == NULL))
2541     {
2542         return E_INVALIDARG;
2543     }
2544
2545     // ELT3 hooks beat Whidbey and Whidbey hooks beat Everett hooks.  So if any ELT3 or 
2546     // Whidbey hooks were set (SetEnterLeaveFunctionHooks3(WithInfo) or SetEnterLeaveFunctionHooks2), 
2547     // this should be a noop
2548     if ((m_pEnter3            != NULL) ||
2549         (m_pEnter3WithInfo    != NULL) ||
2550         (m_pLeave3            != NULL) || 
2551         (m_pLeave3WithInfo    != NULL) || 
2552         (m_pTailcall3         != NULL) ||
2553         (m_pTailcall3WithInfo != NULL) ||
2554         (m_pEnter2            != NULL) ||
2555         (m_pLeave2            != NULL) || 
2556         (m_pTailcall2         != NULL))
2557     {
2558         return S_OK;
2559     }
2560
2561     // Always save onto the function pointers, since we won't know if the profiler
2562     // is going to tracking enter/leave until after it returns from Initialize
2563     m_pEnter = pFuncEnter;
2564     m_pLeave = pFuncLeave;
2565     m_pTailcall = pFuncTailcall;
2566
2567     return DetermineAndSetEnterLeaveFunctionHooksForJit();
2568 }
2569
2570 //---------------------------------------------------------------------------------------
2571 //
2572 // The Info method SetEnterLeaveFunctionHooks2() simply defers to this function to do the
2573 // real work.
2574 //
2575 // Arguments:
2576 //     (same as specified in the public API docs)
2577 //
2578 // Return Value:
2579 //     HRESULT indicating success / failure to return straight through to the profiler
2580 //
2581
2582 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFuncEnter,
2583                                                            FunctionLeave2 * pFuncLeave,
2584                                                            FunctionTailcall2 * pFuncTailcall)
2585 {
2586     CONTRACTL
2587     {
2588         NOTHROW;
2589         GC_NOTRIGGER;
2590         MODE_ANY;
2591         EE_THREAD_NOT_REQUIRED;
2592         CANNOT_TAKE_LOCK;
2593     }
2594     CONTRACTL_END;
2595
2596     // You have to be setting at least one hook
2597     if ((pFuncEnter == NULL) && (pFuncLeave == NULL) && (pFuncTailcall == NULL))
2598     {
2599         return E_INVALIDARG;
2600     }
2601
2602     // ELT3 hooks beat Whidbey.  So if any ELT3 hooks were set (SetEnterLeaveFunctionHooks3(WithInfo)), 
2603     // this should be a noop
2604     if ((m_pEnter3            != NULL) ||
2605         (m_pEnter3WithInfo    != NULL) ||
2606         (m_pLeave3            != NULL) || 
2607         (m_pLeave3WithInfo    != NULL) || 
2608         (m_pTailcall3         != NULL) ||
2609         (m_pTailcall3WithInfo != NULL))
2610     {
2611         return S_OK;
2612     }
2613
2614     // Always save onto the function pointers, since we won't know if the profiler
2615     // is going to track enter/leave until after it returns from Initialize
2616     m_pEnter2 = pFuncEnter;
2617     m_pLeave2 = pFuncLeave;
2618     m_pTailcall2 = pFuncTailcall;
2619
2620     // Whidbey hooks override Everett hooks
2621     m_pEnter = NULL;
2622     m_pLeave = NULL;
2623     m_pTailcall = NULL;
2624
2625     return DetermineAndSetEnterLeaveFunctionHooksForJit();
2626 }
2627
2628 //---------------------------------------------------------------------------------------
2629 //
2630 // The Info method SetEnterLeaveFunctionHooks3() simply defers to this function to do the
2631 // real work.
2632 //
2633 // Arguments:
2634 //     (same as specified in the public API docs)
2635 //
2636 // Return Value:
2637 //     HRESULT indicating success / failure to return straight through to the profiler
2638 //
2639
2640 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFuncEnter3,
2641                                                            FunctionLeave3 * pFuncLeave3,
2642                                                            FunctionTailcall3 * pFuncTailcall3)
2643 {
2644     CONTRACTL
2645     {
2646         NOTHROW;
2647         GC_NOTRIGGER;
2648         MODE_ANY;
2649         EE_THREAD_NOT_REQUIRED;
2650         CANNOT_TAKE_LOCK;
2651     }
2652     CONTRACTL_END;
2653
2654     // You have to be setting at least one hook
2655     if ((pFuncEnter3    == NULL) &&
2656         (pFuncLeave3    == NULL) &&
2657         (pFuncTailcall3 == NULL))
2658     {
2659         return E_INVALIDARG;
2660     }
2661
2662     if (CORProfilerELT3SlowPathEnabled())
2663     {
2664         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2665     }
2666
2667     // Always save onto the function pointers, since we won't know if the profiler
2668     // is going to track enter/leave until after it returns from Initialize
2669     m_pEnter3    = pFuncEnter3;
2670     m_pLeave3    = pFuncLeave3;
2671     m_pTailcall3 = pFuncTailcall3;
2672     m_pEnter3WithInfo    = NULL;
2673     m_pLeave3WithInfo    = NULL;
2674     m_pTailcall3WithInfo = NULL;
2675
2676     // ELT3 hooks override Whidbey hooks and Everett hooks.
2677     m_pEnter2    = NULL;
2678     m_pLeave2    = NULL;
2679     m_pTailcall2 = NULL;
2680     m_pEnter     = NULL;
2681     m_pLeave     = NULL;
2682     m_pTailcall  = NULL;
2683
2684     return DetermineAndSetEnterLeaveFunctionHooksForJit();
2685 }
2686
2687
2688 //---------------------------------------------------------------------------------------
2689 //
2690 // The Info method SetEnterLeaveFunctionHooks3() simply defers to this function to do the
2691 // real work.
2692 //
2693 // Arguments:
2694 //     (same as specified in the public API docs)
2695 //
2696 // Return Value:
2697 //     HRESULT indicating success / failure to return straight through to the profiler
2698 //
2699
2700 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter3WithInfo * pFuncEnter3WithInfo,
2701                                                                    FunctionLeave3WithInfo * pFuncLeave3WithInfo,
2702                                                                    FunctionTailcall3WithInfo * pFuncTailcall3WithInfo)
2703 {
2704     CONTRACTL
2705     {
2706         NOTHROW;
2707         GC_NOTRIGGER;
2708         MODE_ANY;
2709         EE_THREAD_NOT_REQUIRED;
2710         CANNOT_TAKE_LOCK;
2711     }
2712     CONTRACTL_END;
2713
2714     // You have to be setting at least one hook
2715     if ((pFuncEnter3WithInfo    == NULL) &&
2716         (pFuncLeave3WithInfo    == NULL) &&
2717         (pFuncTailcall3WithInfo == NULL))
2718     {
2719         return E_INVALIDARG;
2720     }
2721
2722     if (!CORProfilerELT3SlowPathEnabled())
2723     {
2724         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2725     }
2726
2727     // Always save onto the function pointers, since we won't know if the profiler
2728     // is going to track enter/leave until after it returns from Initialize
2729     m_pEnter3WithInfo    = pFuncEnter3WithInfo;
2730     m_pLeave3WithInfo    = pFuncLeave3WithInfo;
2731     m_pTailcall3WithInfo = pFuncTailcall3WithInfo;
2732     m_pEnter3    = NULL;
2733     m_pLeave3    = NULL;
2734     m_pTailcall3 = NULL;
2735
2736     // ELT3 hooks override Whidbey hooks and Everett hooks.
2737     m_pEnter2    = NULL;
2738     m_pLeave2    = NULL;
2739     m_pTailcall2 = NULL;
2740     m_pEnter     = NULL;
2741     m_pLeave     = NULL;
2742     m_pTailcall  = NULL;
2743
2744     return DetermineAndSetEnterLeaveFunctionHooksForJit();
2745 }
2746
2747
2748
2749 //---------------------------------------------------------------------------------------
2750 //
2751 // ************************
2752 // Public callback wrappers
2753 // ************************
2754 //
2755 // NOTE: All public callback wrappers must follow the rules stated at the top
2756 // of this file!
2757
2758 // See corprof.idl / MSDN for detailed comments about each of these public
2759 // functions, their parameters, return values, etc.
2760
2761
2762
2763 //---------------------------------------------------------------------------------------
2764 // INITIALIZE CALLBACKS
2765 //
2766
2767 HRESULT EEToProfInterfaceImpl::Initialize()
2768 {
2769     CONTRACTL
2770     {
2771         // Yay!
2772         NOTHROW;
2773
2774         // Yay!
2775         GC_TRIGGERS;
2776
2777         // Yay!
2778         MODE_PREEMPTIVE;
2779
2780         // Yay!
2781         CAN_TAKE_LOCK;
2782
2783         // Yay!
2784         ASSERT_NO_EE_LOCKS_HELD();
2785
2786     }
2787     CONTRACTL_END;
2788
2789     CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileInitializing,
2790         (LF_CORPROF, 
2791          LL_INFO10, 
2792          "**PROF: Calling profiler's Initialize() method.\n"));
2793
2794     _ASSERTE(m_pProfToEE != NULL);
2795
2796     // Startup initialization occurs before an EEThread object is created for this
2797     // thread.
2798     _ASSERTE(GetThreadNULLOk() == NULL);
2799
2800     {
2801         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
2802         // whose try/catch blocks aren't visible to the contract system        
2803         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
2804         return m_pCallback2->Initialize(m_pProfToEE);
2805     }
2806 }
2807
2808
2809 HRESULT EEToProfInterfaceImpl::InitializeForAttach(void * pvClientData, UINT cbClientData)
2810 {
2811     CONTRACTL
2812     {
2813         // Yay!
2814         NOTHROW;
2815
2816         // Yay!
2817         GC_TRIGGERS;
2818
2819         // Yay!
2820         MODE_PREEMPTIVE;
2821
2822         // Yay!
2823         CAN_TAKE_LOCK;
2824
2825         // Yay!
2826         ASSERT_NO_EE_LOCKS_HELD();
2827
2828     }
2829     CONTRACTL_END;
2830
2831     CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileInitializing,
2832         (LF_CORPROF, 
2833          LL_INFO10, 
2834          "**PROF: Calling profiler's InitializeForAttach() method.\n"));
2835
2836     _ASSERTE(m_pProfToEE != NULL);
2837
2838     // Attach initialization occurs on the AttachThread, which does not have an EEThread
2839     // object
2840     _ASSERTE(GetThreadNULLOk() == NULL);
2841
2842     // Should only be called on profilers that support ICorProfilerCallback3
2843     _ASSERTE(m_pCallback3 != NULL);
2844
2845     HRESULT hr = E_UNEXPECTED;
2846
2847     // This wraps the profiler's InitializeForAttach callback in a try / catch. Although
2848     // most profiler calls are not protected, this initial callback IS, since it's cheap
2849     // to do so (this is only called once per attach of a profiler), and it would be nice to
2850     // avoid tearing down the entire process when attaching a profiler that may pass back
2851     // bogus vtables.
2852     EX_TRY
2853     {
2854         hr = m_pCallback3->InitializeForAttach(m_pProfToEE, pvClientData, cbClientData);
2855     }
2856     EX_CATCH
2857     {
2858         hr = E_UNEXPECTED;
2859     }
2860     // Intentionally swallowing all exceptions, as we don't want a poorly-written
2861     // profiler that throws or AVs on attach to cause the entire process to go away.
2862     EX_END_CATCH(SwallowAllExceptions);
2863
2864     return hr;
2865 }
2866
2867 HRESULT EEToProfInterfaceImpl::ProfilerAttachComplete()
2868 {
2869     CONTRACTL
2870     {
2871         // Yay!
2872         NOTHROW;
2873
2874         // Yay!
2875         GC_TRIGGERS;
2876
2877         // Yay!
2878         MODE_PREEMPTIVE;
2879
2880         // Yay!
2881         CAN_TAKE_LOCK;
2882
2883         // Yay!
2884         ASSERT_NO_EE_LOCKS_HELD();
2885
2886     }
2887     CONTRACTL_END;
2888
2889     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
2890                                 LL_INFO10, 
2891                                 "**PROF: Calling profiler's ProfilerAttachComplete() method.\n"));
2892
2893     // Attach initialization occurs on the AttachThread, which does not have an EEThread
2894     // object
2895     _ASSERTE(GetThreadNULLOk() == NULL);
2896
2897     // Should only be called on profilers that support ICorProfilerCallback3
2898     _ASSERTE(m_pCallback3 != NULL);
2899
2900     HRESULT hr = E_UNEXPECTED;
2901
2902     // This wraps the profiler's ProfilerAttachComplete callback in a try / catch.
2903     // Although most profiler calls are not protected, this early callback IS, since it's
2904     // cheap to do so (this is only called once per attach of a profiler), and it would be
2905     // nice to avoid tearing down the entire process when attaching a profiler that has
2906     // serious troubles initializing itself (e.g., in this case, with processing catch-up
2907     // information).
2908     EX_TRY
2909     {
2910         hr = m_pCallback3->ProfilerAttachComplete();
2911     }
2912     EX_CATCH
2913     {
2914         hr = E_UNEXPECTED;
2915     }
2916     // Intentionally swallowing all exceptions, as we don't want a poorly-written
2917     // profiler that throws or AVs on attach to cause the entire process to go away.
2918     EX_END_CATCH(SwallowAllExceptions);
2919
2920     return hr;
2921 }
2922
2923
2924 //---------------------------------------------------------------------------------------
2925 // THREAD EVENTS
2926 //
2927
2928
2929 HRESULT EEToProfInterfaceImpl::ThreadCreated(ThreadID threadId)
2930 {
2931     CONTRACTL
2932     {
2933         // Yay!
2934         NOTHROW;
2935
2936         // Yay!
2937         GC_TRIGGERS;
2938
2939         // Preemptive mode is particularly important here.  See comment in
2940         // EEToProfInterfaceImpl::ThreadDestroyed for more information.
2941         MODE_PREEMPTIVE;
2942
2943         // Yay!
2944         CAN_TAKE_LOCK;
2945
2946         // Yay!
2947         ASSERT_NO_EE_LOCKS_HELD();
2948
2949     }
2950     CONTRACTL_END;
2951
2952     // Normally these callback wrappers ask IsGCSpecial() and return without calling the
2953     // profiler if true. However, ThreadCreated() is the special case where no caller
2954     // should even get this far for GC Special threads, since our callers need to know to
2955     // avoid the GCX_PREEMP around the call to this function in the first place. See
2956     // code:Thread::m_fGCSpecial
2957     _ASSERTE(!reinterpret_cast<Thread *>(threadId)->IsGCSpecial());
2958
2959     CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId, 
2960                                           (LF_CORPROF, 
2961                                            LL_INFO100, 
2962                                            "**PROF: Notifying profiler of created thread. ThreadId: 0x%p.\n", 
2963                                            threadId));
2964
2965     // Notify the profiler of the newly created thread.
2966     {
2967         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
2968         // whose try/catch blocks aren't visible to the contract system        
2969         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
2970         return m_pCallback2->ThreadCreated(threadId);
2971     }
2972 }
2973
2974 HRESULT EEToProfInterfaceImpl::ThreadDestroyed(ThreadID threadId)
2975 {
2976     CONTRACTL
2977     {
2978         // Yay!
2979         NOTHROW;
2980
2981         // Yay!
2982         GC_TRIGGERS;
2983
2984         // See comment below
2985         MODE_PREEMPTIVE;
2986
2987         // Yay!
2988         CAN_TAKE_LOCK;
2989
2990         // Thread store lock is typically held during this callback
2991
2992     }
2993     CONTRACTL_END;
2994
2995     if (reinterpret_cast<Thread *>(threadId)->IsGCSpecial())
2996         return S_OK;
2997    
2998     // In general, we like callbacks to switch to preemptive before calling into the
2999     // profiler.  And this is particularly important to do in the ThreadCreated &
3000     // ThreadDestroyed callbacks.
3001     //
3002     // The profiler will typically block in the ThreadDestroyed callback, because
3003     // it must coordinate the use of this threadid amongst all profiler
3004     // threads.  For instance, if a separate thread A is walking "this" (via DoStackSnapshot),
3005     // then the profiler must block in ThreadDestroyed until A is finished.  Otherwise,
3006     // "this" will complete its destruction before A's walk is complete.
3007     //
3008     // Since the profiler will block indefinitely in ThreadDestroyed, we need
3009     // to switch to preemptive mode.  Otherwise, if another thread B needs to suspend
3010     // the runtime (due to appdomain unload, GC, etc.), thread B will block
3011     // waiting for "this" (assuming we allow "this" to remain in cooperative mode),
3012     // while the profiler forces "this" to block on thread A from
3013     // the example above.  And thread A may need to block on thread B, since
3014     // the stackwalking occasionally needs to switch to cooperative to access a
3015     // hash map (thus DoStackSnapshot forces the switch to cooperative up-front, before
3016     // the target thread to be walked gets suspended (yet another deadlock possibility)),
3017     // and switching to cooperative requires a wait until an in-progress GC or
3018     // EE suspension is complete.  In other words, allowing "this" to remain
3019     // in cooperative mode could lead to a 3-way deadlock:
3020     //      "this" waits on A
3021     //      A waits on B
3022     //      B waits on "this".
3023     CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId,
3024                                           (LF_CORPROF, 
3025                                            LL_INFO100, 
3026                                            "**PROF: Notifying profiler of destroyed thread. ThreadId: 0x%p.\n", 
3027                                            threadId));
3028
3029     // From now on, issue no more callbacks for this thread
3030     SetProfilerCallbacksAllowedForThread((Thread *) threadId, FALSE);
3031
3032     // Notify the profiler of the destroyed thread
3033     {
3034         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3035         // whose try/catch blocks aren't visible to the contract system        
3036         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3037         return m_pCallback2->ThreadDestroyed(threadId);
3038     }
3039 }
3040
3041 HRESULT EEToProfInterfaceImpl::ThreadAssignedToOSThread(ThreadID managedThreadId,
3042                                                         DWORD osThreadId)
3043 {
3044     CONTRACTL
3045     {
3046         // Yay!
3047         NOTHROW;
3048
3049         // Called by notrigger Thread::DetachThread & CorHost::SwitchOutLogicalThreadState
3050         // which do look to be dangerous times to be triggering a GC
3051         GC_NOTRIGGER;
3052
3053         // This is called in notrigger zones (see above), so it's not safe to switch to preemptive
3054         MODE_ANY;
3055
3056         // Yay!
3057         CAN_TAKE_LOCK;
3058
3059         // Yay!
3060         ASSERT_NO_EE_LOCKS_HELD();
3061
3062     }
3063     CONTRACTL_END;
3064
3065     if (reinterpret_cast<Thread *>(managedThreadId)->IsGCSpecial())
3066         return S_OK;
3067
3068     CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(
3069         kEE2PNoTrigger,
3070         managedThreadId,
3071         (LF_CORPROF, 
3072         LL_INFO100, 
3073         "**PROF: Notifying profiler of thread assignment.  ThreadId: 0x%p, OSThreadId: 0x%08x\n", 
3074         managedThreadId, 
3075         osThreadId));
3076
3077     // Notify the profiler of the thread being assigned to the OS thread
3078     {
3079         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3080         // whose try/catch blocks aren't visible to the contract system        
3081         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3082         return m_pCallback2->ThreadAssignedToOSThread(managedThreadId, osThreadId);
3083     }
3084 }
3085
3086 HRESULT EEToProfInterfaceImpl::ThreadNameChanged(ThreadID managedThreadId,
3087                                                  ULONG cchName,
3088                                                  __in_ecount_opt(cchName) WCHAR name[])
3089 {
3090     CONTRACTL
3091     {
3092         // Yay!
3093         NOTHROW;
3094
3095         // Yay!
3096         GC_TRIGGERS;
3097
3098         // Yay!
3099         MODE_PREEMPTIVE;
3100
3101         // Yay!
3102         CAN_TAKE_LOCK;
3103
3104         // Yay!
3105         ASSERT_NO_EE_LOCKS_HELD();
3106
3107     }
3108     CONTRACTL_END;
3109     
3110     if (reinterpret_cast<Thread *>(managedThreadId)->IsGCSpecial())
3111         return S_OK;
3112
3113     CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(managedThreadId, 
3114                                           (LF_CORPROF, 
3115                                            LL_INFO100, 
3116                                            "**PROF: Notifying profiler of thread name change.\n"));
3117
3118     {
3119         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3120         // whose try/catch blocks aren't visible to the contract system        
3121         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3122         return m_pCallback2->ThreadNameChanged(managedThreadId, cchName, name);
3123     }
3124 }
3125
3126 //---------------------------------------------------------------------------------------
3127 // EE STARTUP/SHUTDOWN EVENTS
3128 //
3129
3130 HRESULT EEToProfInterfaceImpl::Shutdown()
3131 {
3132     CONTRACTL
3133     {
3134         // Yay!
3135         NOTHROW;
3136
3137         // Yay!
3138         GC_TRIGGERS;
3139
3140         // Yay!
3141         MODE_PREEMPTIVE;
3142
3143         // Yay!
3144         CAN_TAKE_LOCK;
3145
3146         // Yay!
3147         ASSERT_NO_EE_LOCKS_HELD();
3148
3149     }
3150     CONTRACTL_END;
3151     
3152     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3153                                 LL_INFO10,
3154                                 "**PROF: Notifying profiler that shutdown is beginning.\n"));
3155
3156     {
3157         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3158         // whose try/catch blocks aren't visible to the contract system        
3159         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3160         return m_pCallback2->Shutdown();
3161     }
3162 }
3163
3164 //---------------------------------------------------------------------------------------
3165 // JIT/FUNCTION EVENTS
3166 //
3167
3168 HRESULT EEToProfInterfaceImpl::FunctionUnloadStarted(FunctionID functionId)
3169 {
3170     _ASSERTE(!"FunctionUnloadStarted() callback no longer issued");
3171     return S_OK;
3172 }
3173
3174 HRESULT EEToProfInterfaceImpl::JITCompilationFinished(FunctionID functionId,
3175                                                       HRESULT hrStatus, 
3176                                                       BOOL fIsSafeToBlock)
3177 {
3178     CONTRACTL
3179     {
3180         // Yay!
3181         NOTHROW;
3182
3183         // Yay!
3184         GC_TRIGGERS;
3185
3186         // Yay!
3187         MODE_PREEMPTIVE;
3188
3189         // Yay!
3190         CAN_TAKE_LOCK;
3191
3192         // The JIT / MethodDesc code likely hold locks while this callback is made
3193
3194     }
3195     CONTRACTL_END;
3196     
3197     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3198                                 LL_INFO1000, 
3199                                 "**PROF: JITCompilationFinished 0x%p, hr=0x%08x.\n", 
3200                                 functionId, 
3201                                 hrStatus));
3202
3203     _ASSERTE(functionId);
3204
3205     {
3206         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3207         // whose try/catch blocks aren't visible to the contract system        
3208         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3209         return m_pCallback2->JITCompilationFinished(functionId, hrStatus, fIsSafeToBlock);
3210     }
3211 }
3212
3213
3214 HRESULT EEToProfInterfaceImpl::JITCompilationStarted(FunctionID functionId,
3215                                                      BOOL fIsSafeToBlock)
3216 {
3217     CONTRACTL
3218     {
3219         // Yay!
3220         NOTHROW;
3221
3222         // Yay!
3223         GC_TRIGGERS;
3224
3225         // Yay!
3226         MODE_PREEMPTIVE;
3227
3228         // Yay!
3229         CAN_TAKE_LOCK;
3230
3231         // The JIT / MethodDesc code likely hold locks while this callback is made
3232
3233     }
3234     CONTRACTL_END;
3235
3236     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3237                                 LL_INFO1000, 
3238                                 "**PROF: JITCompilationStarted 0x%p.\n", 
3239                                 functionId));
3240
3241     // Currently JITCompilationStarted is always called with fIsSafeToBlock==TRUE.  If this ever changes,
3242     // it's safe to remove this assert, but this should serve as a trigger to change our
3243     // public documentation to state that this callback is no longer called in preemptive mode all the time.
3244     _ASSERTE(fIsSafeToBlock);
3245     
3246     _ASSERTE(functionId);
3247
3248     {
3249         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3250         // whose try/catch blocks aren't visible to the contract system        
3251         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3252         return m_pCallback2->JITCompilationStarted(functionId, fIsSafeToBlock);
3253     }
3254 }
3255
3256 HRESULT EEToProfInterfaceImpl::DynamicMethodUnloaded(FunctionID functionId)
3257 {
3258     CONTRACTL
3259     {
3260         THROWS;
3261         GC_TRIGGERS;
3262         MODE_COOPERATIVE; // RuntimeMethodHandle::Destroy (the caller) moves from QCALL to GCX_COOP
3263         CAN_TAKE_LOCK;
3264     }
3265     CONTRACTL_END;
3266
3267     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3268         LL_INFO1000,
3269         "**PROF: DynamicMethodUnloaded 0x%p.\n",
3270         functionId));
3271
3272     _ASSERTE(functionId);
3273
3274     if (m_pCallback9 == NULL)
3275     {
3276         return S_OK;
3277     }
3278
3279     {
3280         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3281         // whose try/catch blocks aren't visible to the contract system        
3282         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3283         return m_pCallback9->DynamicMethodUnloaded(functionId);
3284     }
3285 }
3286
3287 HRESULT EEToProfInterfaceImpl::DynamicMethodJITCompilationFinished(FunctionID functionId,
3288                                                                    HRESULT hrStatus,
3289                                                                    BOOL fIsSafeToBlock)
3290 {
3291     CONTRACTL
3292     {
3293         NOTHROW;
3294         GC_TRIGGERS;
3295         MODE_PREEMPTIVE;
3296         CAN_TAKE_LOCK;
3297
3298         // The JIT / MethodDesc code likely hold locks while this callback is made
3299
3300     }
3301     CONTRACTL_END;
3302     
3303     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3304                                 LL_INFO1000, 
3305                                 "**PROF: DynamicMethodJITCompilationFinished 0x%p.\n", 
3306                                 functionId));
3307
3308     _ASSERTE(functionId);
3309
3310     if (m_pCallback8 == NULL)
3311     {
3312         return S_OK;
3313     }
3314
3315     {
3316         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3317         // whose try/catch blocks aren't visible to the contract system        
3318         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3319         return m_pCallback8->DynamicMethodJITCompilationFinished(functionId, hrStatus, fIsSafeToBlock);
3320     }
3321 }
3322
3323 HRESULT EEToProfInterfaceImpl::DynamicMethodJITCompilationStarted(FunctionID functionId,
3324                                                                   BOOL fIsSafeToBlock,
3325                                                                   LPCBYTE pILHeader,
3326                                                                   ULONG cbILHeader)
3327 {
3328     CONTRACTL
3329     {
3330         NOTHROW;
3331         GC_TRIGGERS;
3332         MODE_PREEMPTIVE;
3333         CAN_TAKE_LOCK;
3334
3335         // The JIT / MethodDesc code likely hold locks while this callback is made
3336
3337     }
3338     CONTRACTL_END;
3339     
3340     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3341                                 LL_INFO1000, 
3342                                 "**PROF: DynamicMethodJITCompilationStarted 0x%p.\n", 
3343                                 functionId));
3344
3345     _ASSERTE(functionId);
3346
3347     // Currently DynamicMethodJITCompilationStarted is always called with fIsSafeToBlock==TRUE.  If this ever changes,
3348     // it's safe to remove this assert, but this should serve as a trigger to change our
3349     // public documentation to state that this callback is no longer called in preemptive mode all the time.
3350     _ASSERTE(fIsSafeToBlock);
3351
3352     if (m_pCallback8 == NULL)
3353     {
3354         return S_OK;
3355     }
3356
3357     {
3358         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3359         // whose try/catch blocks aren't visible to the contract system        
3360         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3361         return m_pCallback8->DynamicMethodJITCompilationStarted(functionId, fIsSafeToBlock, pILHeader, cbILHeader);
3362     }
3363 }
3364
3365 HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchStarted(
3366                                     /* [in] */  FunctionID functionId,
3367                                     /* [out] */ BOOL       *pbUseCachedFunction)
3368 {
3369     CONTRACTL
3370     {
3371         // Yay!
3372         NOTHROW;
3373
3374         // Yay!
3375         GC_TRIGGERS;
3376
3377         // Yay!
3378         MODE_PREEMPTIVE;
3379
3380         // Yay!
3381         CAN_TAKE_LOCK;
3382
3383         // The JIT / MethodDesc code likely hold locks while this callback is made
3384
3385     }
3386     CONTRACTL_END;
3387     
3388     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3389                                 LL_INFO1000, 
3390                                 "**PROF: JITCachedFunctionSearchStarted 0x%p.\n", 
3391                                 functionId));
3392     _ASSERTE(functionId);
3393     _ASSERTE(pbUseCachedFunction != NULL);
3394
3395     {
3396         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3397         // whose try/catch blocks aren't visible to the contract system        
3398         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3399         return m_pCallback2->JITCachedFunctionSearchStarted(functionId, pbUseCachedFunction);
3400     }
3401 }
3402
3403 HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchFinished(
3404                                     /* [in] */  FunctionID functionId,
3405                                     /* [in] */  COR_PRF_JIT_CACHE result)
3406 {
3407     CONTRACTL
3408     {
3409         // Yay!
3410         NOTHROW;
3411
3412         // Yay!
3413         GC_TRIGGERS;
3414
3415         // Yay!
3416         MODE_PREEMPTIVE;
3417
3418         // Yay!
3419         CAN_TAKE_LOCK;
3420
3421         // The JIT / MethodDesc code likely hold locks while this callback is made
3422
3423     }
3424     CONTRACTL_END;
3425     
3426     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3427                                 LL_INFO1000, 
3428                                 "**PROF: JITCachedFunctionSearchFinished 0x%p, %s.\n", 
3429                                 functionId,
3430                                 (result == COR_PRF_CACHED_FUNCTION_FOUND ? 
3431                                     "Cached function found" : 
3432                                     "Cached function not found")));
3433
3434     _ASSERTE(functionId);
3435
3436     {
3437         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3438         // whose try/catch blocks aren't visible to the contract system        
3439         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3440         return m_pCallback2->JITCachedFunctionSearchFinished(functionId, result);
3441     }
3442 }
3443
3444
3445 HRESULT EEToProfInterfaceImpl::JITFunctionPitched(FunctionID functionId)
3446 {
3447     _ASSERTE(!"JITFunctionPitched() callback no longer issued");
3448     return S_OK;
3449 }
3450
3451 HRESULT EEToProfInterfaceImpl::JITInlining(
3452     /* [in] */  FunctionID    callerId,
3453     /* [in] */  FunctionID    calleeId,
3454     /* [out] */ BOOL *        pfShouldInline)
3455 {
3456     CONTRACTL
3457     {
3458         // Yay!
3459         NOTHROW;
3460
3461         // Yay!
3462         GC_TRIGGERS;
3463
3464         // Yay!
3465         MODE_PREEMPTIVE;
3466
3467         // Yay!
3468         CAN_TAKE_LOCK;
3469
3470         // The JIT / MethodDesc code likely hold locks while this callback is made
3471
3472     }
3473     CONTRACTL_END;
3474     
3475     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3476                                 LL_INFO1000, 
3477                                 "**PROF: JITInlining caller: 0x%p, callee: 0x%p.\n", 
3478                                 callerId, 
3479                                 calleeId));
3480
3481     _ASSERTE(callerId);
3482     _ASSERTE(calleeId);
3483
3484     {
3485         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3486         // whose try/catch blocks aren't visible to the contract system        
3487         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3488         return m_pCallback2->JITInlining(callerId, calleeId, pfShouldInline);
3489     }
3490 }
3491
3492 HRESULT EEToProfInterfaceImpl::ReJITCompilationStarted(
3493     /* [in] */  FunctionID    functionId,
3494     /* [in] */  ReJITID       reJitId,
3495     /* [in] */  BOOL          fIsSafeToBlock)
3496 {
3497     CONTRACTL
3498     {
3499         // Yay!
3500         NOTHROW;
3501
3502         // Yay!
3503         GC_TRIGGERS;
3504
3505         // Yay!
3506         MODE_PREEMPTIVE;
3507
3508         // Yay!
3509         CAN_TAKE_LOCK;
3510
3511         // The JIT / MethodDesc code likely hold locks while this callback is made
3512
3513     }
3514     CONTRACTL_END;
3515
3516     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3517                                 LL_INFO1000, 
3518                                 "**PROF: ReJITCompilationStarted 0x%p 0x%p.\n", 
3519                                 functionId, reJitId));
3520
3521     // Should only be called on profilers that support ICorProfilerCallback4
3522     _ASSERTE(m_pCallback4 != NULL);
3523
3524     // Currently ReJITCompilationStarted is always called with fIsSafeToBlock==TRUE.  If this ever changes,
3525     // it's safe to remove this assert, but this should serve as a trigger to change our
3526     // public documentation to state that this callback is no longer called in preemptive mode all the time.
3527     _ASSERTE(fIsSafeToBlock);
3528     
3529     _ASSERTE(functionId);
3530     _ASSERTE(reJitId);
3531
3532     {
3533         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3534         // whose try/catch blocks aren't visible to the contract system        
3535         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3536         return m_pCallback4->ReJITCompilationStarted(functionId, reJitId, fIsSafeToBlock);
3537     }
3538 }
3539
3540 HRESULT EEToProfInterfaceImpl::GetReJITParameters(
3541     /* [in] */  ModuleID      moduleId,
3542     /* [in] */  mdMethodDef   methodId,
3543     /* [in] */  ICorProfilerFunctionControl *
3544                                   pFunctionControl)
3545 {
3546     CONTRACTL
3547     {
3548         // Yay!
3549         NOTHROW;
3550
3551         // Yay!
3552         GC_TRIGGERS;
3553
3554         // Yay!
3555         MODE_PREEMPTIVE;
3556
3557         // Yay!
3558         CAN_TAKE_LOCK;
3559
3560         // The ReJIT code holds a lock while this callback is made
3561
3562     }
3563     CONTRACTL_END;
3564
3565     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3566                                 LL_INFO1000, 
3567                                 "**PROF: GetReJITParameters 0x%p 0x%p.\n", 
3568                                 moduleId, methodId));
3569
3570     // Should only be called on profilers that support ICorProfilerCallback4
3571     _ASSERTE(m_pCallback4 != NULL);
3572
3573     _ASSERTE(moduleId);
3574
3575     {
3576         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3577         // whose try/catch blocks aren't visible to the contract system        
3578         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3579         return m_pCallback4->GetReJITParameters(moduleId, methodId, pFunctionControl);
3580     }
3581 }
3582
3583 HRESULT EEToProfInterfaceImpl::ReJITCompilationFinished(
3584     /* [in] */  FunctionID    functionId,
3585     /* [in] */  ReJITID       reJitId,
3586     /* [in] */  HRESULT       hrStatus,
3587     /* [in] */  BOOL          fIsSafeToBlock)
3588 {
3589     CONTRACTL
3590     {
3591         // Yay!
3592         NOTHROW;
3593
3594         // Yay!
3595         GC_TRIGGERS;
3596
3597         // Yay!
3598         MODE_PREEMPTIVE;
3599
3600         // Yay!
3601         CAN_TAKE_LOCK;
3602
3603         // ReJit holds a lock as well as possibly others...
3604
3605     }
3606     CONTRACTL_END;
3607
3608     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3609                                 LL_INFO1000, 
3610                                 "**PROF: ReJITCompilationFinished 0x%p 0x%p hr=0x%x.\n", 
3611                                 functionId, reJitId, hrStatus));
3612
3613     // Should only be called on profilers that support ICorProfilerCallback4
3614     _ASSERTE(m_pCallback4 != NULL);
3615
3616     _ASSERTE(functionId);
3617     _ASSERTE(reJitId);
3618
3619     {
3620         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3621         // whose try/catch blocks aren't visible to the contract system        
3622         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3623         return m_pCallback4->ReJITCompilationFinished(functionId, reJitId, hrStatus, fIsSafeToBlock);
3624     }
3625 }
3626
3627
3628 HRESULT EEToProfInterfaceImpl::ReJITError(
3629     /* [in] */  ModuleID      moduleId,
3630     /* [in] */  mdMethodDef   methodId,
3631     /* [in] */  FunctionID    functionId,
3632     /* [in] */  HRESULT       hrStatus)
3633 {
3634     CONTRACTL
3635     {
3636         // Yay!
3637         NOTHROW;
3638
3639         // Yay!
3640         GC_TRIGGERS;
3641
3642         // Yay!
3643         MODE_PREEMPTIVE;
3644
3645         // Yay!
3646         CAN_TAKE_LOCK;
3647
3648     }
3649     CONTRACTL_END;
3650
3651     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3652                                 LL_INFO1000, 
3653                                 "**PROF: ReJITError 0x%p 0x%x 0x%p 0x%x.\n", 
3654                                 moduleId, methodId, functionId, hrStatus));
3655
3656     // Should only be called on profilers that support ICorProfilerCallback4
3657     _ASSERTE(m_pCallback4 != NULL);
3658
3659     {
3660         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3661         // whose try/catch blocks aren't visible to the contract system        
3662         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3663         return m_pCallback4->ReJITError(moduleId, methodId, functionId, hrStatus);
3664     }
3665 }
3666
3667 //---------------------------------------------------------------------------------------
3668 // MODULE EVENTS
3669 //
3670
3671 HRESULT EEToProfInterfaceImpl::ModuleLoadStarted(ModuleID moduleId)
3672 {
3673     CONTRACTL
3674     {
3675         // Yay!
3676         NOTHROW;
3677
3678         // Yay!
3679         GC_TRIGGERS;
3680
3681         // This has historically not run in preemptive, and is called from cooperative-mode 
3682         // functions. However, since we're triggers, it might actually be safe to consider 
3683         // letting this run in preemptive mode.
3684         MODE_COOPERATIVE;
3685         
3686         // Yay!
3687         CAN_TAKE_LOCK;
3688
3689         // Yay!
3690         ASSERT_NO_EE_LOCKS_HELD();
3691
3692     }
3693     CONTRACTL_END;
3694     
3695     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3696                                 LL_INFO10, 
3697                                 "**PROF: ModuleLoadStarted 0x%p.\n", 
3698                                 moduleId));
3699
3700     _ASSERTE(moduleId != 0);
3701
3702     {
3703         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3704         // whose try/catch blocks aren't visible to the contract system        
3705         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3706         return m_pCallback2->ModuleLoadStarted(moduleId);
3707     }
3708 }
3709
3710
3711 HRESULT EEToProfInterfaceImpl::ModuleLoadFinished(
3712     ModuleID    moduleId,
3713     HRESULT        hrStatus)
3714 {
3715     CONTRACTL
3716     {
3717         // Yay!
3718         NOTHROW;
3719
3720         // Yay!
3721         GC_TRIGGERS;
3722
3723         // Yay!
3724         MODE_PREEMPTIVE;
3725         
3726         // Yay!
3727         CAN_TAKE_LOCK;
3728
3729         // Yay!
3730         ASSERT_NO_EE_LOCKS_HELD();
3731
3732     }
3733     CONTRACTL_END;
3734     
3735     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3736                                 LL_INFO10, 
3737                                 "**PROF: ModuleLoadFinished 0x%p.\n", 
3738                                 moduleId));
3739
3740     _ASSERTE(moduleId != 0);
3741
3742     {
3743         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3744         // whose try/catch blocks aren't visible to the contract system        
3745         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3746         return m_pCallback2->ModuleLoadFinished(moduleId, hrStatus);
3747     }
3748 }
3749
3750
3751
3752 HRESULT EEToProfInterfaceImpl::ModuleUnloadStarted(
3753     ModuleID    moduleId)
3754 {
3755     CONTRACTL
3756     {
3757         // Yay!
3758         NOTHROW;
3759
3760         // Yay!
3761         GC_TRIGGERS;
3762
3763         // Yay!
3764         MODE_PREEMPTIVE;
3765
3766         // Yay!
3767         CAN_TAKE_LOCK;
3768
3769         // Yay!
3770         ASSERT_NO_EE_LOCKS_HELD();
3771
3772     }
3773     CONTRACTL_END;
3774     
3775     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3776                                 LL_INFO10, 
3777                                 "**PROF: ModuleUnloadStarted 0x%p.\n", 
3778                                 moduleId));
3779
3780     _ASSERTE(moduleId != 0);
3781
3782     {
3783         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3784         // whose try/catch blocks aren't visible to the contract system        
3785         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3786         return m_pCallback2->ModuleUnloadStarted(moduleId);
3787     }
3788 }
3789
3790
3791 HRESULT EEToProfInterfaceImpl::ModuleUnloadFinished(
3792     ModuleID    moduleId,
3793     HRESULT        hrStatus)
3794 {
3795     CONTRACTL
3796     {
3797         // Yay!
3798         NOTHROW;
3799
3800         // Yay!
3801         GC_TRIGGERS;
3802
3803         // Yay!
3804         MODE_PREEMPTIVE;
3805
3806         // Yay!
3807         CAN_TAKE_LOCK;
3808
3809         // Yay!
3810         ASSERT_NO_EE_LOCKS_HELD();
3811
3812     }
3813     CONTRACTL_END;
3814     
3815     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3816                                 LL_INFO10, 
3817                                 "**PROF: ModuleUnloadFinished 0x%p.\n", 
3818                                 moduleId));
3819     _ASSERTE(moduleId != 0);
3820     {
3821         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3822         // whose try/catch blocks aren't visible to the contract system        
3823         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3824         return m_pCallback2->ModuleUnloadFinished(moduleId, hrStatus);
3825     }
3826 }
3827
3828
3829 HRESULT EEToProfInterfaceImpl::ModuleAttachedToAssembly(
3830     ModuleID    moduleId,
3831     AssemblyID  AssemblyId)
3832 {
3833     CONTRACTL
3834     {
3835         // Yay!
3836         NOTHROW;
3837
3838         // Yay!
3839         GC_TRIGGERS;
3840
3841         // Yay!
3842         MODE_PREEMPTIVE;
3843
3844         // Yay!
3845         CAN_TAKE_LOCK;
3846
3847         // Yay!
3848         ASSERT_NO_EE_LOCKS_HELD();
3849
3850     }
3851     CONTRACTL_END;
3852
3853     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3854                                 LL_INFO10, 
3855                                 "**PROF: ModuleAttachedToAssembly 0x%p, 0x%p.\n", 
3856                                 moduleId, 
3857                                 AssemblyId));
3858
3859     _ASSERTE(moduleId != 0);
3860
3861     {
3862         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3863         // whose try/catch blocks aren't visible to the contract system        
3864         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3865         return m_pCallback2->ModuleAttachedToAssembly(moduleId, AssemblyId);
3866     }
3867 }
3868
3869 HRESULT EEToProfInterfaceImpl::ModuleInMemorySymbolsUpdated(ModuleID moduleId)
3870 {
3871     CONTRACTL
3872     {
3873         // Yay!
3874         NOTHROW;
3875
3876         // Yay!
3877         GC_TRIGGERS;
3878
3879         // Yay!
3880         MODE_PREEMPTIVE;
3881
3882         // Yay!
3883         CAN_TAKE_LOCK;
3884
3885     }
3886     CONTRACTL_END;
3887
3888     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3889         LL_INFO10,
3890         "**PROF: ModuleInMemorySymbolsUpdated.  moduleId: 0x%p.\n",
3891         moduleId
3892         ));
3893     HRESULT hr = S_OK;
3894
3895     _ASSERTE(IsCallback7Supported());
3896
3897     {
3898         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3899         // whose try/catch blocks aren't visible to the contract system        
3900         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3901         hr = m_pCallback7->ModuleInMemorySymbolsUpdated(moduleId);
3902     }
3903
3904     return hr;
3905 }
3906
3907 //---------------------------------------------------------------------------------------
3908 // CLASS EVENTS
3909 //
3910
3911 HRESULT EEToProfInterfaceImpl::ClassLoadStarted(
3912     ClassID     classId)
3913 {
3914     CONTRACTL
3915     {
3916         // Yay!
3917         NOTHROW;
3918
3919         // Yay!
3920         GC_TRIGGERS;
3921
3922         // Yay!
3923         MODE_PREEMPTIVE;
3924
3925         // Yay!
3926         CAN_TAKE_LOCK;
3927
3928         // UnresolvedClassLock typically held during this callback
3929
3930     }
3931     CONTRACTL_END;
3932
3933     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3934                                 LL_INFO100, 
3935                                 "**PROF: ClassLoadStarted 0x%p.\n", 
3936                                 classId));
3937
3938     _ASSERTE(classId);
3939
3940     {
3941         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3942         // whose try/catch blocks aren't visible to the contract system        
3943         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3944         return m_pCallback2->ClassLoadStarted(classId);
3945     }
3946 }
3947
3948
3949 HRESULT EEToProfInterfaceImpl::ClassLoadFinished(
3950     ClassID     classId,
3951     HRESULT     hrStatus)
3952 {
3953     CONTRACTL
3954     {
3955         // Yay!
3956         NOTHROW;
3957
3958         // Yay!
3959         GC_TRIGGERS;
3960
3961         // Yay!
3962         MODE_PREEMPTIVE;
3963
3964         // Yay!
3965         CAN_TAKE_LOCK;
3966
3967         // UnresolvedClassLock typically held during this callback
3968
3969     }
3970     CONTRACTL_END;
3971     
3972     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
3973                                 LL_INFO100, 
3974                                 "**PROF: ClassLoadFinished 0x%p, 0x%08x.\n", 
3975                                 classId, 
3976                                 hrStatus));
3977
3978     _ASSERTE(classId);
3979
3980     {
3981         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3982         // whose try/catch blocks aren't visible to the contract system        
3983         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3984         return m_pCallback2->ClassLoadFinished(classId, hrStatus);
3985     }
3986 }
3987
3988
3989 HRESULT EEToProfInterfaceImpl::ClassUnloadStarted(
3990     ClassID     classId)
3991 {
3992     CONTRACTL
3993     {
3994         // Yay!
3995         NOTHROW;
3996
3997         // Yay!
3998         GC_TRIGGERS;
3999
4000         // Yay!
4001         MODE_PREEMPTIVE;
4002
4003         // Yay!
4004         CAN_TAKE_LOCK;
4005
4006         // Although not typical, it's possible for UnresolvedClassLock to be held
4007         // during this callback.  This can occur if, during the class load, an
4008         // exception is thrown, and EEClass::Destruct is called from the catch clause
4009         // inside ClassLoader::CreateTypeHandleForTypeDefThrowing.
4010
4011     }
4012     CONTRACTL_END;
4013     
4014     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4015                                 LL_INFO100, 
4016                                 "**PROF: ClassUnloadStarted 0x%p.\n", 
4017                                 classId));
4018
4019     _ASSERTE(classId);
4020
4021     {
4022         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4023         // whose try/catch blocks aren't visible to the contract system        
4024         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4025         return m_pCallback2->ClassUnloadStarted(classId);
4026     }
4027 }
4028
4029
4030 HRESULT EEToProfInterfaceImpl::ClassUnloadFinished(
4031     ClassID     classId,
4032     HRESULT     hrStatus)
4033 {
4034     CONTRACTL
4035     {
4036         // Yay!
4037         NOTHROW;
4038
4039         // Yay!
4040         GC_TRIGGERS;
4041
4042         // Yay!
4043         MODE_PREEMPTIVE;
4044
4045         // Yay!
4046         CAN_TAKE_LOCK;
4047
4048         // Locks can be held when this is called.  See comment in ClassUnloadStarted
4049
4050     }
4051     CONTRACTL_END;
4052     
4053     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4054                                 LL_INFO100, 
4055                                 "**PROF: ClassUnloadFinished 0x%p, 0x%08x.\n", 
4056                                 classId, 
4057                                 hrStatus));
4058
4059     _ASSERTE(classId);
4060
4061     {
4062         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4063         // whose try/catch blocks aren't visible to the contract system        
4064         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4065         return m_pCallback2->ClassUnloadFinished(classId, hrStatus);
4066     }
4067 }
4068
4069 //---------------------------------------------------------------------------------------
4070 // APPDOMAIN EVENTS
4071 //
4072
4073 HRESULT EEToProfInterfaceImpl::AppDomainCreationStarted(
4074     AppDomainID appDomainId)
4075 {
4076     CONTRACTL
4077     {
4078         // Yay!
4079         NOTHROW;
4080
4081         // Yay!
4082         GC_TRIGGERS;
4083
4084         // Yay!
4085         MODE_PREEMPTIVE;
4086
4087         // Yay!
4088         CAN_TAKE_LOCK;
4089
4090         // Yay!
4091         ASSERT_NO_EE_LOCKS_HELD();
4092
4093     }
4094     CONTRACTL_END;
4095  
4096     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4097                                 LL_INFO10, 
4098                                 "**PROF: AppDomainCreationStarted 0x%p.\n", 
4099                                 appDomainId));
4100
4101     _ASSERTE(appDomainId != 0);
4102
4103     {
4104         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4105         // whose try/catch blocks aren't visible to the contract system        
4106         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4107         return m_pCallback2->AppDomainCreationStarted(appDomainId);
4108     }
4109 }
4110
4111
4112 HRESULT EEToProfInterfaceImpl::AppDomainCreationFinished(
4113     AppDomainID appDomainId,
4114     HRESULT     hrStatus)
4115 {
4116     CONTRACTL
4117     {
4118         // Yay!
4119         NOTHROW;
4120
4121         // Yay!
4122         GC_TRIGGERS;
4123
4124         // Yay!
4125         MODE_PREEMPTIVE;
4126
4127         // Yay!
4128         CAN_TAKE_LOCK;
4129
4130         // Yay!
4131         ASSERT_NO_EE_LOCKS_HELD();
4132
4133     }
4134     CONTRACTL_END;
4135     
4136     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4137                                 LL_INFO10, 
4138                                 "**PROF: AppDomainCreationFinished 0x%p, 0x%08x.\n", 
4139                                 appDomainId, 
4140                                 hrStatus));
4141
4142     _ASSERTE(appDomainId != 0);
4143
4144     {
4145         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4146         // whose try/catch blocks aren't visible to the contract system        
4147         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4148         return m_pCallback2->AppDomainCreationFinished(appDomainId, hrStatus);
4149     }
4150 }
4151
4152 HRESULT EEToProfInterfaceImpl::AppDomainShutdownStarted(
4153     AppDomainID appDomainId)
4154 {
4155     CONTRACTL
4156     {
4157         // Yay!
4158         NOTHROW;
4159
4160         // Yay!
4161         GC_TRIGGERS;
4162
4163         // Yay!
4164         MODE_PREEMPTIVE;
4165
4166         // Yay!
4167         CAN_TAKE_LOCK;
4168
4169         // Yay!
4170         ASSERT_NO_EE_LOCKS_HELD();
4171
4172     }
4173     CONTRACTL_END;
4174     
4175     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4176                                 LL_INFO10, 
4177                                 "**PROF: AppDomainShutdownStarted 0x%p.\n", 
4178                                 appDomainId));
4179
4180     _ASSERTE(appDomainId != 0);
4181
4182     {
4183         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4184         // whose try/catch blocks aren't visible to the contract system        
4185         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4186         return m_pCallback2->AppDomainShutdownStarted(appDomainId);
4187     }
4188 }
4189
4190 HRESULT EEToProfInterfaceImpl::AppDomainShutdownFinished(
4191     AppDomainID appDomainId,
4192     HRESULT     hrStatus)
4193 {
4194     CONTRACTL
4195     {
4196         // Yay!
4197         NOTHROW;
4198
4199         // Yay!
4200         GC_TRIGGERS;
4201
4202         // Yay!
4203         MODE_PREEMPTIVE;
4204
4205         // Yay!
4206         CAN_TAKE_LOCK;
4207
4208         // Yay!
4209         ASSERT_NO_EE_LOCKS_HELD();
4210
4211     }
4212     CONTRACTL_END;
4213     
4214     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4215                                 LL_INFO10, 
4216                                 "**PROF: AppDomainShutdownFinished 0x%p, 0x%08x.\n", 
4217                                 appDomainId, 
4218                                 hrStatus));
4219
4220     _ASSERTE(appDomainId != 0);
4221
4222     {
4223         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4224         // whose try/catch blocks aren't visible to the contract system        
4225         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4226         return m_pCallback2->AppDomainShutdownFinished(appDomainId, hrStatus);
4227     }
4228 }
4229
4230 //---------------------------------------------------------------------------------------
4231 // ASSEMBLY EVENTS
4232 //
4233
4234 HRESULT EEToProfInterfaceImpl::AssemblyLoadStarted(
4235     AssemblyID  assemblyId)
4236 {
4237     CONTRACTL
4238     {
4239         // Yay!
4240         NOTHROW;
4241
4242         // Yay!
4243         GC_TRIGGERS;
4244
4245         // This has historically not run in preemptive, and is called from cooperative-mode 
4246         // functions. However, since we're triggers, it might actually be safe to consider 
4247         // letting this run in preemptive mode.
4248         MODE_COOPERATIVE;
4249
4250         // Yay!
4251         CAN_TAKE_LOCK;
4252
4253         // Yay!
4254         ASSERT_NO_EE_LOCKS_HELD();
4255
4256     }
4257     CONTRACTL_END;
4258     
4259     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4260                                 LL_INFO10, 
4261                                 "**PROF: AssemblyLoadStarted 0x%p.\n", 
4262                                 assemblyId));
4263
4264     _ASSERTE(assemblyId != 0);
4265
4266     {
4267         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4268         // whose try/catch blocks aren't visible to the contract system        
4269         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4270         return m_pCallback2->AssemblyLoadStarted(assemblyId);
4271     }
4272 }
4273
4274 HRESULT EEToProfInterfaceImpl::AssemblyLoadFinished(
4275     AssemblyID  assemblyId,
4276     HRESULT     hrStatus)
4277 {
4278     CONTRACTL
4279     {
4280         // Yay!
4281         NOTHROW;
4282
4283         // Yay!
4284         GC_TRIGGERS;
4285
4286         // This has historically not run in preemptive, and is called from cooperative-mode 
4287         // functions. However, since we're triggers, it might actually be safe to consider 
4288         // letting this run in preemptive mode.
4289         MODE_COOPERATIVE;
4290
4291         // Yay!
4292         CAN_TAKE_LOCK;
4293
4294         // Yay!
4295         ASSERT_NO_EE_LOCKS_HELD();
4296
4297     }
4298     CONTRACTL_END;
4299
4300     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4301                                 LL_INFO10, 
4302                                 "**PROF: AssemblyLoadFinished 0x%p, 0x%08x.\n", 
4303                                 assemblyId, 
4304                                 hrStatus));
4305
4306     _ASSERTE(assemblyId != 0);
4307
4308     {
4309         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4310         // whose try/catch blocks aren't visible to the contract system        
4311         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4312         return m_pCallback2->AssemblyLoadFinished(assemblyId, hrStatus);
4313     }
4314 }
4315
4316 HRESULT EEToProfInterfaceImpl::AssemblyUnloadStarted(
4317     AssemblyID  assemblyId)
4318 {
4319     CONTRACTL
4320     {
4321         // Yay!
4322         NOTHROW;
4323
4324         // Yay!
4325         GC_TRIGGERS;
4326
4327         // Yay!
4328         MODE_PREEMPTIVE;
4329
4330         // Yay!
4331         CAN_TAKE_LOCK;
4332
4333         // Yay!
4334         ASSERT_NO_EE_LOCKS_HELD();
4335
4336     }
4337     CONTRACTL_END;
4338     
4339     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4340                                 LL_INFO10, 
4341                                 "**PROF: AssemblyUnloadStarted 0x%p.\n",
4342                                 assemblyId));
4343
4344     _ASSERTE(assemblyId != 0);
4345
4346     {
4347         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4348         // whose try/catch blocks aren't visible to the contract system        
4349         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4350         return m_pCallback2->AssemblyUnloadStarted(assemblyId);
4351     }
4352 }
4353
4354 HRESULT EEToProfInterfaceImpl::AssemblyUnloadFinished(
4355     AssemblyID  assemblyId,
4356     HRESULT     hrStatus)
4357 {
4358     CONTRACTL
4359     {
4360         // Yay!
4361         NOTHROW;
4362
4363         // Yay!
4364         GC_TRIGGERS;
4365
4366         // Yay!
4367         MODE_PREEMPTIVE;
4368
4369         // Yay!
4370         CAN_TAKE_LOCK;
4371
4372         // Yay!
4373         ASSERT_NO_EE_LOCKS_HELD();
4374
4375     }
4376     CONTRACTL_END;
4377
4378     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4379                                 LL_INFO10,
4380                                 "**PROF: AssemblyUnloadFinished 0x%p, 0x%08x.\n",
4381                                 assemblyId,
4382                                 hrStatus));
4383
4384     _ASSERTE(assemblyId != 0);
4385
4386     {
4387         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4388         // whose try/catch blocks aren't visible to the contract system        
4389         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4390         return m_pCallback2->AssemblyUnloadFinished(assemblyId, hrStatus);
4391     }
4392 }
4393
4394 //---------------------------------------------------------------------------------------
4395 // TRANSITION EVENTS
4396 //
4397
4398 HRESULT EEToProfInterfaceImpl::UnmanagedToManagedTransition(
4399     FunctionID functionId,
4400     COR_PRF_TRANSITION_REASON reason)
4401 {
4402     CONTRACTL
4403     {
4404         // Yay!
4405         NOTHROW;
4406
4407         // Yay!
4408         GC_TRIGGERS;
4409
4410         // Yay!
4411         MODE_PREEMPTIVE;
4412
4413         // Yay!
4414         CAN_TAKE_LOCK;
4415
4416         // Yay!
4417         ASSERT_NO_EE_LOCKS_HELD();
4418
4419     }
4420     CONTRACTL_END;
4421
4422     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4423                                 LL_INFO10000, 
4424                                 "**PROF: UnmanagedToManagedTransition 0x%p.\n", 
4425                                 functionId));
4426
4427     _ASSERTE(reason == COR_PRF_TRANSITION_CALL || reason == COR_PRF_TRANSITION_RETURN);
4428
4429     {
4430         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4431         // whose try/catch blocks aren't visible to the contract system        
4432         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4433         return m_pCallback2->UnmanagedToManagedTransition(functionId, reason);
4434     }
4435 }
4436
4437 HRESULT EEToProfInterfaceImpl::ManagedToUnmanagedTransition(
4438     FunctionID functionId,
4439     COR_PRF_TRANSITION_REASON reason)
4440 {
4441     CONTRACTL
4442     {
4443         // Yay!
4444         NOTHROW;
4445
4446         // Yay!
4447         GC_TRIGGERS;
4448
4449         // Yay!
4450         MODE_PREEMPTIVE;
4451
4452         // Yay!
4453         CAN_TAKE_LOCK;
4454
4455         // Yay!
4456         ASSERT_NO_EE_LOCKS_HELD();
4457
4458     }
4459     CONTRACTL_END;
4460     
4461     _ASSERTE(reason == COR_PRF_TRANSITION_CALL || reason == COR_PRF_TRANSITION_RETURN);
4462
4463     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4464                                 LL_INFO10000, 
4465                                 "**PROF: ManagedToUnmanagedTransition 0x%p.\n",
4466                                 functionId));
4467
4468     {
4469         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4470         // whose try/catch blocks aren't visible to the contract system        
4471         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4472         return m_pCallback2->ManagedToUnmanagedTransition(functionId, reason);
4473     }
4474 }
4475
4476 //---------------------------------------------------------------------------------------
4477 // EXCEPTION EVENTS
4478 //
4479
4480 HRESULT EEToProfInterfaceImpl::ExceptionThrown(
4481     ObjectID thrownObjectId)
4482 {
4483     CONTRACTL
4484     {
4485         // Yay!
4486         NOTHROW;
4487
4488         // Yay!
4489         GC_TRIGGERS;
4490
4491         // Preemptive mode would be bad, dude.  There's an objectId in the param list!
4492         MODE_COOPERATIVE;
4493
4494         // Yay!
4495         CAN_TAKE_LOCK;
4496
4497         // Yay!
4498         ASSERT_NO_EE_LOCKS_HELD();
4499
4500     }
4501     CONTRACTL_END;
4502
4503     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4504                                 LL_INFO1000, 
4505                                 "**PROF: ExceptionThrown. ObjectID: 0x%p. ThreadID: 0x%p\n",
4506                                 thrownObjectId, 
4507                                 GetThread()));
4508
4509     {
4510         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4511         // whose try/catch blocks aren't visible to the contract system        
4512         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4513         return m_pCallback2->ExceptionThrown(thrownObjectId);
4514     }
4515 }
4516
4517 HRESULT EEToProfInterfaceImpl::ExceptionSearchFunctionEnter(
4518     FunctionID functionId)
4519 {
4520     CONTRACTL
4521     {
4522         // Yay!
4523         NOTHROW;
4524
4525         // Yay!
4526         GC_TRIGGERS;
4527
4528         // Yay!
4529         MODE_PREEMPTIVE;
4530
4531         // Yay!
4532         CAN_TAKE_LOCK;
4533
4534         // Yay!
4535         ASSERT_NO_EE_LOCKS_HELD();
4536
4537     }
4538     CONTRACTL_END;
4539
4540     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4541                                 LL_INFO1000, 
4542                                 "**PROF: ExceptionSearchFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4543                                 GetThread(), 
4544                                 functionId));
4545
4546     {
4547         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4548         // whose try/catch blocks aren't visible to the contract system        
4549         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4550         return m_pCallback2->ExceptionSearchFunctionEnter(functionId);
4551     }
4552 }
4553
4554 HRESULT EEToProfInterfaceImpl::ExceptionSearchFunctionLeave()
4555 {
4556     CONTRACTL
4557     {
4558         // Yay!
4559         NOTHROW;
4560
4561         // Yay!
4562         GC_TRIGGERS;
4563
4564         // Yay!
4565         MODE_PREEMPTIVE;
4566
4567         // Yay!
4568         CAN_TAKE_LOCK;
4569
4570         // Yay!
4571         ASSERT_NO_EE_LOCKS_HELD();
4572
4573     }
4574     CONTRACTL_END;
4575
4576     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4577                                 LL_INFO1000, 
4578                                 "**PROF: ExceptionSearchFunctionLeave. ThreadID: 0x%p\n",
4579                                 GetThread()));
4580
4581     {
4582         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4583         // whose try/catch blocks aren't visible to the contract system        
4584         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4585         return m_pCallback2->ExceptionSearchFunctionLeave();
4586     }
4587 }
4588
4589 HRESULT EEToProfInterfaceImpl::ExceptionSearchFilterEnter(FunctionID functionId)
4590 {
4591     CONTRACTL
4592     {
4593         // Yay!
4594         NOTHROW;
4595
4596         // Yay!
4597         GC_TRIGGERS;
4598
4599         // Yay!
4600         MODE_PREEMPTIVE;
4601
4602         // Yay!
4603         CAN_TAKE_LOCK;
4604
4605         // Yay!
4606         ASSERT_NO_EE_LOCKS_HELD();
4607
4608     }
4609     CONTRACTL_END;
4610     
4611     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4612                                 LL_INFO1000, 
4613                                 "**PROF: ExceptionSearchFilterEnter. ThreadID: 0x%p, functionId: 0x%p\n", 
4614                                 GetThread(), 
4615                                 functionId));
4616
4617     {
4618         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4619         // whose try/catch blocks aren't visible to the contract system        
4620         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4621         return m_pCallback2->ExceptionSearchFilterEnter(functionId);
4622     }
4623 }
4624
4625 HRESULT EEToProfInterfaceImpl::ExceptionSearchFilterLeave()
4626 {
4627     CONTRACTL
4628     {
4629         // Yay!
4630         NOTHROW;
4631
4632         // Yay!
4633         GC_TRIGGERS;
4634
4635         // Yay!
4636         MODE_PREEMPTIVE;
4637
4638         // Yay!
4639         CAN_TAKE_LOCK;
4640
4641         // Yay!
4642         ASSERT_NO_EE_LOCKS_HELD();
4643
4644     }
4645     CONTRACTL_END;
4646     
4647     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4648                                 LL_INFO1000, 
4649                                 "**PROF: ExceptionFilterLeave. ThreadID: 0x%p\n",
4650                                 GetThread()));
4651
4652     {
4653         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4654         // whose try/catch blocks aren't visible to the contract system        
4655         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4656         return m_pCallback2->ExceptionSearchFilterLeave();
4657     }
4658 }
4659
4660 HRESULT EEToProfInterfaceImpl::ExceptionSearchCatcherFound(FunctionID functionId)
4661 {
4662     CONTRACTL
4663     {
4664         // Yay!
4665         NOTHROW;
4666
4667         // Yay!
4668         GC_TRIGGERS;
4669
4670         // Yay!
4671         MODE_PREEMPTIVE;
4672
4673         // Yay!
4674         CAN_TAKE_LOCK;
4675
4676         // Yay!
4677         ASSERT_NO_EE_LOCKS_HELD();
4678
4679     }
4680     CONTRACTL_END;
4681     
4682     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4683                                 LL_INFO1000, 
4684                                 "**PROF: ExceptionSearchCatcherFound.  ThreadID: 0x%p\n",
4685                                 GetThread()));
4686
4687     {
4688         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4689         // whose try/catch blocks aren't visible to the contract system        
4690         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4691         return m_pCallback2->ExceptionSearchCatcherFound(functionId);
4692     }
4693 }
4694
4695 HRESULT EEToProfInterfaceImpl::ExceptionOSHandlerEnter(FunctionID functionId)
4696 {
4697     _ASSERTE(!"ExceptionOSHandlerEnter() callback no longer issued");
4698     return S_OK;
4699 }
4700
4701 HRESULT EEToProfInterfaceImpl::ExceptionOSHandlerLeave(FunctionID functionId)
4702 {
4703     _ASSERTE(!"ExceptionOSHandlerLeave() callback no longer issued");
4704     return S_OK;
4705 }
4706
4707 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFunctionEnter(FunctionID functionId)
4708 {
4709     CONTRACTL
4710     {
4711         // Yay!
4712         NOTHROW;
4713
4714         // Called by COMPlusUnwindCallback, which is notrigger
4715         GC_NOTRIGGER;
4716
4717         // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4718         // Thus, the profiler cannot block on this call.
4719         MODE_ANY;
4720
4721         // Yay!
4722         CAN_TAKE_LOCK;
4723
4724         // Yay!
4725         ASSERT_NO_EE_LOCKS_HELD();
4726
4727     }
4728     CONTRACTL_END;
4729
4730     CLR_TO_PROFILER_ENTRYPOINT_EX(
4731         kEE2PNoTrigger,
4732         (LF_CORPROF, 
4733         LL_INFO1000, 
4734         "**PROF: ExceptionUnwindFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n", 
4735         GetThread(),
4736         functionId));
4737
4738     {
4739         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4740         // whose try/catch blocks aren't visible to the contract system        
4741         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4742         return m_pCallback2->ExceptionUnwindFunctionEnter(functionId);
4743     }
4744 }
4745
4746 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFunctionLeave()
4747 {
4748     CONTRACTL
4749     {
4750         // Yay!
4751         NOTHROW;
4752
4753         // Called by COMPlusUnwindCallback, which is notrigger
4754         GC_NOTRIGGER;
4755
4756         // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4757         // Thus, the profiler cannot block on this call.
4758         MODE_ANY;
4759
4760         // Yay!
4761         CAN_TAKE_LOCK;
4762
4763         // Yay!
4764         ASSERT_NO_EE_LOCKS_HELD();
4765
4766     }
4767     CONTRACTL_END;
4768
4769     CLR_TO_PROFILER_ENTRYPOINT_EX(
4770         kEE2PNoTrigger,
4771         (LF_CORPROF, 
4772         LL_INFO1000, 
4773         "**PROF: ExceptionUnwindFunctionLeave. ThreadID: 0x%p\n",
4774         GetThread()));
4775
4776     {
4777         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4778         // whose try/catch blocks aren't visible to the contract system        
4779         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4780         return m_pCallback2->ExceptionUnwindFunctionLeave();
4781     }
4782 }
4783
4784 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFinallyEnter(FunctionID functionId)
4785 {
4786     CONTRACTL
4787     {
4788         // Yay!
4789         NOTHROW;
4790
4791         // Called by COMPlusUnwindCallback, which is notrigger
4792         GC_NOTRIGGER;
4793
4794         // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4795         // Thus, the profiler cannot block on this call.
4796         MODE_COOPERATIVE;
4797
4798         // Yay!
4799         CAN_TAKE_LOCK;
4800
4801         // Yay!
4802         ASSERT_NO_EE_LOCKS_HELD();
4803
4804     }
4805     CONTRACTL_END;
4806
4807     CLR_TO_PROFILER_ENTRYPOINT_EX(
4808         kEE2PNoTrigger,
4809         (LF_CORPROF, 
4810         LL_INFO1000, 
4811         "**PROF: ExceptionUnwindFinallyEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4812         GetThread(),
4813         functionId));
4814
4815     {
4816         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4817         // whose try/catch blocks aren't visible to the contract system        
4818         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4819         return m_pCallback2->ExceptionUnwindFinallyEnter(functionId);
4820     }
4821 }
4822
4823 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFinallyLeave()
4824 {
4825     CONTRACTL
4826     {
4827         // Yay!
4828         NOTHROW;
4829
4830         // Called by COMPlusUnwindCallback, which is notrigger
4831         GC_NOTRIGGER;
4832
4833         // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4834         // Thus, the profiler cannot block on this call.
4835         MODE_COOPERATIVE;
4836
4837         // Yay!
4838         CAN_TAKE_LOCK;
4839
4840         // Yay!
4841         ASSERT_NO_EE_LOCKS_HELD();
4842
4843     }
4844     CONTRACTL_END;
4845
4846     CLR_TO_PROFILER_ENTRYPOINT_EX(
4847         kEE2PNoTrigger,
4848         (LF_CORPROF, 
4849         LL_INFO1000, 
4850         "**PROF: ExceptionUnwindFinallyLeave. ThreadID: 0x%p\n",
4851         GetThread()));
4852
4853     {
4854         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4855         // whose try/catch blocks aren't visible to the contract system        
4856         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4857         return m_pCallback2->ExceptionUnwindFinallyLeave();
4858     }
4859 }
4860
4861 HRESULT EEToProfInterfaceImpl::ExceptionCatcherEnter(FunctionID functionId, ObjectID objectId)
4862 {
4863     CONTRACTL
4864     {
4865         // Yay!
4866         NOTHROW;
4867
4868         // Called by COMPlusUnwindCallback, which is notrigger
4869         GC_NOTRIGGER;
4870
4871         // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4872         // Thus, the profiler cannot block on this call.
4873         MODE_COOPERATIVE;
4874
4875         // Yay!
4876         CAN_TAKE_LOCK;
4877
4878         // Yay!
4879         ASSERT_NO_EE_LOCKS_HELD();
4880
4881     }
4882     CONTRACTL_END;
4883
4884     CLR_TO_PROFILER_ENTRYPOINT_EX(
4885         kEE2PNoTrigger,
4886         (LF_CORPROF, 
4887         LL_INFO1000, "**PROF: ExceptionCatcherEnter.        ThreadID: 0x%p, functionId: 0x%p\n",
4888         GetThread(), 
4889         functionId));
4890
4891     {
4892         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4893         // whose try/catch blocks aren't visible to the contract system        
4894         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4895         return m_pCallback2->ExceptionCatcherEnter(functionId, objectId);
4896     }
4897 }
4898
4899 HRESULT EEToProfInterfaceImpl::ExceptionCatcherLeave()
4900 {
4901     CONTRACTL
4902     {
4903         // Yay!
4904         NOTHROW;
4905
4906         // Yay!
4907         GC_TRIGGERS;
4908
4909         // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4910         // Thus, the profiler cannot block on this call.
4911         MODE_COOPERATIVE;
4912
4913         // Yay!
4914         CAN_TAKE_LOCK;
4915
4916         // Yay!
4917         ASSERT_NO_EE_LOCKS_HELD();
4918
4919     }
4920     CONTRACTL_END;
4921
4922     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4923                                 LL_INFO1000, 
4924                                 "**PROF: ExceptionCatcherLeave.        ThreadID: 0x%p\n",
4925                                 GetThread()));
4926
4927
4928     {
4929         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4930         // whose try/catch blocks aren't visible to the contract system        
4931         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4932         return m_pCallback2->ExceptionCatcherLeave();
4933     }
4934 }
4935
4936
4937 //---------------------------------------------------------------------------------------
4938 // COM Callable Wrapper EVENTS
4939 //
4940
4941 HRESULT EEToProfInterfaceImpl::COMClassicVTableCreated(
4942     /* [in] */ ClassID classId,
4943     /* [in] */ REFGUID implementedIID,
4944     /* [in] */ void *pVTable,
4945     /* [in] */ ULONG cSlots)
4946 {
4947     CONTRACTL
4948     {
4949         // Yay!
4950         NOTHROW;
4951
4952         // Yay!
4953         GC_TRIGGERS;
4954
4955         // Yay!
4956         MODE_PREEMPTIVE;
4957
4958         // Yay!
4959         CAN_TAKE_LOCK;
4960
4961         // Yay!
4962         ASSERT_NO_EE_LOCKS_HELD();
4963
4964     }
4965     CONTRACTL_END;
4966
4967     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
4968                                 LL_INFO100, 
4969                                 "**PROF: COMClassicWrapperCreated %#x %#08x... %#x %d.\n",
4970                                 classId, 
4971                                 implementedIID.Data1, 
4972                                 pVTable, 
4973                                 cSlots));
4974
4975     {
4976         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4977         // whose try/catch blocks aren't visible to the contract system        
4978         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4979         return m_pCallback2->COMClassicVTableCreated(classId, implementedIID, pVTable, cSlots);
4980     }
4981 }
4982
4983 HRESULT EEToProfInterfaceImpl::COMClassicVTableDestroyed(
4984     /* [in] */ ClassID classId,
4985     /* [in] */ REFGUID implementedIID,
4986     /* [in] */ void *pVTable)
4987 {
4988     CONTRACTL
4989     {
4990         // Yay!
4991         NOTHROW;
4992
4993         // Yay!
4994         GC_TRIGGERS;
4995
4996         // Yay!
4997         MODE_PREEMPTIVE;
4998
4999         // Yay!
5000         CAN_TAKE_LOCK;
5001
5002         // Yay!
5003         ASSERT_NO_EE_LOCKS_HELD();
5004
5005     }
5006     CONTRACTL_END;
5007
5008     // NOTE: There is no problem with this code, and it is ready and willing
5009     // to be called.  However, this callback is intentionally not being 
5010     // issued currently.  See comment in ComMethodTable::Cleanup() for more
5011     // information.
5012
5013     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5014                                 LL_INFO100, 
5015                                 "**PROF: COMClassicWrapperDestroyed %#x %#08x... %#x.\n",
5016                                 classId, 
5017                                 implementedIID.Data1, 
5018                                 pVTable));
5019
5020     {
5021         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5022         // whose try/catch blocks aren't visible to the contract system        
5023         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5024         return m_pCallback2->COMClassicVTableDestroyed(classId, implementedIID, pVTable);
5025     }
5026 }
5027
5028
5029 //---------------------------------------------------------------------------------------
5030 // GC THREADING EVENTS
5031 //
5032
5033 HRESULT EEToProfInterfaceImpl::RuntimeSuspendStarted(
5034     COR_PRF_SUSPEND_REASON suspendReason)
5035 {
5036     CONTRACTL
5037     {
5038         // Yay!
5039         NOTHROW;
5040
5041         // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
5042         // not to allow a GC to occur while we're suspending / resuming the runtime, this is
5043         // the thread trying to do a GC.  So if the profiler tries to trigger another GC from
5044         // this thread at this time, we might see potential recursion or deadlock.
5045         GC_NOTRIGGER;
5046
5047         MODE_ANY;
5048
5049         // Yay!
5050         CAN_TAKE_LOCK;
5051
5052         // Thread store lock is typically held during this callback
5053
5054     }
5055     CONTRACTL_END;
5056
5057     CLR_TO_PROFILER_ENTRYPOINT_EX(
5058         kEE2PNoTrigger,
5059         (LF_CORPROF, 
5060         LL_INFO100, 
5061         "**PROF: RuntimeSuspendStarted. ThreadID 0x%p.\n",
5062         GetThread()));
5063
5064     {
5065         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5066         // whose try/catch blocks aren't visible to the contract system        
5067         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5068         return m_pCallback2->RuntimeSuspendStarted(suspendReason);
5069     }
5070 }
5071
5072 HRESULT EEToProfInterfaceImpl::RuntimeSuspendFinished()
5073 {
5074     CONTRACTL
5075     {
5076         // Yay!
5077         NOTHROW;
5078
5079         // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
5080         // not to allow a GC to occur while we're suspending / resuming the runtime, this is
5081         // the thread trying to do a GC.  So if the profiler tries to trigger another GC from
5082         // this thread at this time, we might see potential recursion or deadlock.
5083         GC_NOTRIGGER;
5084
5085         MODE_ANY;
5086
5087         // Yay!
5088         CAN_TAKE_LOCK;
5089
5090         // Thread store lock is typically held during this callback
5091
5092     }
5093     CONTRACTL_END;
5094
5095     CLR_TO_PROFILER_ENTRYPOINT_EX(
5096         kEE2PNoTrigger,
5097         (LF_CORPROF, 
5098         LL_INFO100, 
5099         "**PROF: RuntimeSuspendFinished. ThreadID 0x%p.\n",
5100         GetThread()));
5101
5102
5103     {
5104         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5105         // whose try/catch blocks aren't visible to the contract system        
5106         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5107         return m_pCallback2->RuntimeSuspendFinished();
5108     }
5109 }
5110
5111 HRESULT EEToProfInterfaceImpl::RuntimeSuspendAborted()
5112 {
5113     CONTRACTL
5114     {
5115         // Yay!
5116         NOTHROW;
5117
5118         // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
5119         // not to allow a GC to occur while we're suspending / resuming the runtime, this is
5120         // the thread trying to do a GC.  So if the profiler tries to trigger another GC from
5121         // this thread at this time, we might see potential recursion or deadlock.
5122         GC_NOTRIGGER;
5123
5124         // NOTE: I have no empirical data for gc mode: none of the self-host BVTs call this
5125         // So for now, assume this is callable in any mode.
5126         // This has historically not caused a mode change to preemptive, and is called from
5127         // cooperative-mode functions.  Also, switching to preemptive while we're suspending
5128         // the runtime just seems like a bad idea.
5129         MODE_ANY;
5130
5131         // Yay!
5132         CAN_TAKE_LOCK;
5133
5134         // Thread store lock is typically held during this callback
5135
5136     }
5137     CONTRACTL_END;
5138
5139     CLR_TO_PROFILER_ENTRYPOINT_EX(
5140         kEE2PNoTrigger,
5141         (LF_CORPROF, 
5142         LL_INFO100, 
5143         "**PROF: RuntimeSuspendAborted. ThreadID 0x%p.\n",
5144         GetThread()));
5145
5146     {
5147         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5148         // whose try/catch blocks aren't visible to the contract system        
5149         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5150         return m_pCallback2->RuntimeSuspendAborted();
5151     }
5152 }
5153
5154 HRESULT EEToProfInterfaceImpl::RuntimeResumeStarted()
5155 {
5156     CONTRACTL
5157     {
5158         // Yay!
5159         NOTHROW;
5160
5161         // Yay!
5162         GC_TRIGGERS;
5163
5164         // This has historically not caused a mode change to preemptive, and is called from
5165         // cooperative-mode functions.  Also, switching to preemptive while we're resuming
5166         // the runtime just seems like a bad idea.
5167         MODE_ANY;
5168
5169         // Yay!
5170         CAN_TAKE_LOCK;
5171
5172         // Thread store lock is typically held during this callback
5173
5174     }
5175     CONTRACTL_END;
5176
5177     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5178                                 LL_INFO100, 
5179                                 "**PROF: RuntimeResumeStarted. ThreadID 0x%p.\n",
5180                                 GetThread()));
5181
5182     {
5183         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5184         // whose try/catch blocks aren't visible to the contract system        
5185         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5186         return m_pCallback2->RuntimeResumeStarted();
5187     }
5188 }
5189
5190 HRESULT EEToProfInterfaceImpl::RuntimeResumeFinished()
5191 {
5192     CONTRACTL
5193     {
5194         // Yay!
5195         NOTHROW;
5196
5197         // Yay!
5198         GC_TRIGGERS;
5199
5200         // Yay!
5201         MODE_PREEMPTIVE;
5202
5203         // Yay!
5204         CAN_TAKE_LOCK;
5205
5206         // Thread store lock is typically held during this callback
5207
5208     }
5209     CONTRACTL_END;
5210
5211     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5212                                 LL_INFO100, 
5213                                 "**PROF: RuntimeResumeFinished. ThreadID 0x%p.\n",
5214                                 GetThread()));
5215
5216     {
5217         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5218         // whose try/catch blocks aren't visible to the contract system        
5219         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5220         return m_pCallback2->RuntimeResumeFinished();
5221     }
5222 }
5223
5224 HRESULT EEToProfInterfaceImpl::RuntimeThreadSuspended(ThreadID suspendedThreadId)
5225 {
5226     CONTRACTL
5227     {
5228         // Yay!
5229         NOTHROW;
5230
5231         // Called by Thread::SuspendThread, which is notrigger.
5232         GC_NOTRIGGER;
5233
5234         // Although I've verified we're called from both coop and preemp, we need to
5235         // avoid switching to preemptive to satisfy our notrigger paths.
5236         MODE_ANY;
5237
5238         // Yay!
5239         CAN_TAKE_LOCK;
5240
5241         // Thread store lock is typically held during this callback
5242
5243     }
5244     CONTRACTL_END;
5245
5246     if (reinterpret_cast<Thread *>(suspendedThreadId)->IsGCSpecial())
5247         return S_OK;
5248
5249     // NOTE: We cannot use the standard CLR_TO_PROFILER_ENTRYPOINT macro here because
5250     // we might be called at a time when profiler callbacks have been disallowed for
5251     // this thread.  So we cannot simply ASSERT that callbacks are allowed (as this macro
5252     // does).  Instead, we must explicitly check for this condition and return gracefully
5253     // if callbacks are disallowed.  So the macro is unwrapped here manually
5254
5255     CHECK_PROFILER_STATUS(kEE2PNone);
5256
5257     LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadSuspended. ThreadID 0x%p.\n",
5258          suspendedThreadId));
5259
5260     // NOTE: We're notrigger, so we cannot switch to preemptive mode.
5261     
5262     // We may have already indicated to the profiler that this thread has died, but 
5263     // the runtime may continue to suspend this thread during the process of destroying
5264     // the thread, so we do not want to indicate to the profiler these suspensions.
5265     if (!ProfilerCallbacksAllowedForThread((Thread *) suspendedThreadId))
5266     {
5267         return S_OK;
5268     }
5269
5270     // Remaining essentials from our entrypoint macros with kEE2PNoTrigger flag
5271     SetCallbackStateFlagsHolder csf(COR_PRF_CALLBACKSTATE_INCALLBACK);
5272     _ASSERTE(m_pCallback2 != NULL);
5273
5274     {
5275         // SCOPE: ForbidSuspendThreadHolder
5276
5277         // The ForbidSuspendThreadHolder prevents deadlocks under the following scenario:
5278         // 1) Thread A blocks waiting for the current GC to complete (this can happen if A is trying to
5279         //      switch to cooperative during a GC). 
5280         // 2) This causes us to send a RuntimeThreadSuspended callback to the profiler.  (Although
5281         //      A isn't technically being "suspended", this blocking is considered suspension as far as the
5282         //      profapi is concerned.)
5283         // 3) Profiler, in turn, may take one of its own private locks to synchronize this callback with
5284         //      the profiler's attempt to hijack thread A.  Specifically, the profiler knows it's not allowed
5285         //      to hijack A if A is getting suspended by the runtime, because this suspension might be due to
5286         //      the GC trying to hijack A.  And if the GC tries to hijack A at the same time as the profiler
5287         //      hijacking A and the profiler wins, then GC asserts because A is no longer at the IP that
5288         //      the GC thought (VsWhidbey 428477, 429741)
5289         // 4) Meanwhile, thread B (GC thread) is suspending the runtime, and calls Thread::SuspendThread()
5290         //      on A.  This is the bad thing we're trying to avoid, because when this happens, we call into
5291         //      the profiler AGAIN with RuntimeThreadSuspended for thread A, and the profiler again
5292         //      tries to grab the lock it acquired in step 3).   Yes, at this point we now have two simultaneous
5293         //      calls into the profiler's RuntimeThreadSuspended() callback.  One saying A is suspending A
5294         //      (3 above), and one saying B is suspending A (this step (4)).  The problem is that A is now officially
5295         //      hard suspended, OS-style, so the lock acquired on 3) ain't never getting released until
5296         //      A is resumed.  But A won't be resumed until B resumes it.  And B won't resume A until
5297         //      the profiler returns from its RuntimeThreadSuspended callback.  And  the profiler
5298         //      can't return from its RuntimeThreadSuspended callback until it acquires this lock it tried to
5299         //      acquire in 4).  And it can't acquire this lock until A is finally resumed so that the acquire
5300         //      from 3) is released.  Have we gone in a circle yet?
5301         // In order to avoid 4) we inc the ForbidSuspendThread count during 3) to prevent the hard suspension
5302         // (4) from occurring until 3) is completely done.  It's sufficient to determine we're in 3) by noting
5303         // whether the callback is reporting that a thread is "suspending itself" (i.e., suspendedThreadId == threadId)
5304
5305         ForbidSuspendThreadHolder forbidSuspendThread((Thread *) suspendedThreadId == GetThread());
5306
5307         {
5308             // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5309             // whose try/catch blocks aren't visible to the contract system        
5310             PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5311             return m_pCallback2->RuntimeThreadSuspended(suspendedThreadId);
5312         }
5313     }
5314 }
5315
5316 HRESULT EEToProfInterfaceImpl::RuntimeThreadResumed(ThreadID resumedThreadId)
5317 {
5318     CONTRACTL
5319     {
5320         // Yay!
5321         NOTHROW;
5322
5323         // This gets called in response to another profapi function:
5324         // ICorProfilerInfo2::DoStackSnapshot!  And that dude is called asynchronously and
5325         // must therefore never cause a GC.
5326         // Other reasons for notrigger: also called by notrigger dudes Thread::SysStartSuspendForDebug,
5327         // CheckSuspended, Thread::IsExecutingWithinCer, Thread::IsExecutingWithinCer,
5328         // UnwindFrames
5329         GC_NOTRIGGER;
5330
5331         // Although we cannot trigger, verified empirically that this called coop & preemp
5332         MODE_ANY;
5333
5334         // Yay!
5335         CAN_TAKE_LOCK;
5336
5337         // Thread store lock is typically held during this callback
5338
5339     }
5340     CONTRACTL_END;
5341
5342     if (reinterpret_cast<Thread *>(resumedThreadId)->IsGCSpecial())
5343         return S_OK;
5344
5345     // NOTE: We cannot use the standard CLR_TO_PROFILER_ENTRYPOINT macro here because
5346     // we might be called at a time when profiler callbacks have been disallowed for
5347     // this thread.  So we cannot simply ASSERT that callbacks are allowed (as this macro
5348     // does).  Instead, we must explicitly check for this condition and return gracefully
5349     // if callbacks are disallowed.  So the macro is unwrapped here manually
5350
5351     CHECK_PROFILER_STATUS(kEE2PNone);
5352
5353     LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadResumed. ThreadID 0x%p.\n", resumedThreadId));
5354
5355     // NOTE: We're notrigger, so we cannot switch to preemptive mode.
5356
5357     // We may have already indicated to the profiler that this thread has died, but 
5358     // the runtime may resume this thread during the process of destroying
5359     // the thread, so we do not want to indicate to the profiler these resumes.
5360     if (!ProfilerCallbacksAllowedForThread((Thread *) resumedThreadId))
5361     {
5362         return S_OK;
5363     }
5364
5365     // Remaining essentials from our entrypoint macros with kEE2PNoTrigger flag
5366     SetCallbackStateFlagsHolder csf(COR_PRF_CALLBACKSTATE_INCALLBACK);
5367     _ASSERTE(m_pCallback2 != NULL);
5368
5369     {
5370         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5371         // whose try/catch blocks aren't visible to the contract system        
5372         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5373         return m_pCallback2->RuntimeThreadResumed(resumedThreadId);
5374     }
5375 }
5376
5377 //---------------------------------------------------------------------------------------
5378 // REMOTING
5379 //
5380
5381 HRESULT EEToProfInterfaceImpl::RemotingClientInvocationStarted()
5382 {
5383     CONTRACTL
5384     {
5385         // Yay!
5386         NOTHROW;
5387
5388         // Yay!
5389         GC_TRIGGERS;
5390
5391         // Yay!
5392         MODE_PREEMPTIVE;
5393
5394         // Yay!
5395         CAN_TAKE_LOCK;
5396
5397         // Yay!
5398         ASSERT_NO_EE_LOCKS_HELD();
5399
5400     }
5401     CONTRACTL_END;
5402
5403     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5404                                 LL_INFO1000, 
5405                                 "**PROF: RemotingClientInvocationStarted. ThreadID: 0x%p\n",
5406                                 GetThread()));
5407
5408     {
5409         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5410         // whose try/catch blocks aren't visible to the contract system        
5411         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5412         return m_pCallback2->RemotingClientInvocationStarted();
5413     }
5414 }
5415
5416 HRESULT EEToProfInterfaceImpl::RemotingClientSendingMessage(GUID *pCookie, BOOL fIsAsync)
5417 {
5418     CONTRACTL
5419     {
5420         // Yay!
5421         NOTHROW;
5422
5423         // Yay!
5424         GC_TRIGGERS;
5425
5426         // Yay!
5427         MODE_PREEMPTIVE;
5428
5429         // Yay!
5430         CAN_TAKE_LOCK;
5431
5432         // Yay!
5433         ASSERT_NO_EE_LOCKS_HELD();
5434
5435     }
5436     CONTRACTL_END;
5437
5438     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5439                                 LL_INFO1000, 
5440                                 "**PROF: RemotingClientSendingMessage. ThreadID: 0x%p\n", 
5441                                 GetThread()));
5442
5443     {
5444         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5445         // whose try/catch blocks aren't visible to the contract system        
5446         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5447         return m_pCallback2->RemotingClientSendingMessage(pCookie, fIsAsync);
5448     }
5449 }
5450
5451 HRESULT EEToProfInterfaceImpl::RemotingClientReceivingReply(GUID * pCookie, BOOL fIsAsync)
5452 {
5453     CONTRACTL
5454     {
5455         // Yay!
5456         NOTHROW;
5457
5458         // Yay!
5459         GC_TRIGGERS;
5460
5461         // Yay!
5462         MODE_PREEMPTIVE;
5463
5464         // Yay!
5465         CAN_TAKE_LOCK;
5466
5467         // Yay!
5468         ASSERT_NO_EE_LOCKS_HELD();
5469
5470     }
5471     CONTRACTL_END;
5472
5473     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5474                                 LL_INFO1000, 
5475                                 "**PROF: RemotingClientReceivingReply. ThreadID: 0x%p\n", 
5476                                 GetThread()));
5477
5478     {
5479         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5480         // whose try/catch blocks aren't visible to the contract system        
5481         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5482         return m_pCallback2->RemotingClientReceivingReply(pCookie, fIsAsync);
5483     }
5484 }
5485
5486 HRESULT EEToProfInterfaceImpl::RemotingClientInvocationFinished()
5487 {
5488     CONTRACTL
5489     {
5490         // Yay!
5491         NOTHROW;
5492
5493         // Yay!
5494         GC_TRIGGERS;
5495
5496         // Yay!
5497         MODE_PREEMPTIVE;
5498
5499         // Yay!
5500         CAN_TAKE_LOCK;
5501
5502         // Yay!
5503         ASSERT_NO_EE_LOCKS_HELD();
5504
5505     }
5506     CONTRACTL_END;
5507
5508     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5509                                 LL_INFO1000, 
5510                                 "**PROF: RemotingClientInvocationFinished. ThreadID: 0x%p\n",
5511                                 GetThread()));
5512
5513     {
5514         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5515         // whose try/catch blocks aren't visible to the contract system        
5516         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5517         return m_pCallback2->RemotingClientInvocationFinished();
5518     }
5519 }
5520
5521 HRESULT EEToProfInterfaceImpl::RemotingServerReceivingMessage(GUID *pCookie, BOOL fIsAsync)
5522 {
5523     CONTRACTL
5524     {
5525         // Yay!
5526         NOTHROW;
5527
5528         // Yay!
5529         GC_TRIGGERS;
5530
5531         // Yay!
5532         MODE_PREEMPTIVE;
5533
5534         // Yay!
5535         CAN_TAKE_LOCK;
5536
5537         // Yay!
5538         ASSERT_NO_EE_LOCKS_HELD();
5539
5540     }
5541     CONTRACTL_END;
5542
5543     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5544                                 LL_INFO1000, 
5545                                 "**PROF: RemotingServerReceivingMessage. ThreadID: 0x%p\n", 
5546                                 GetThread()));
5547
5548     {
5549         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5550         // whose try/catch blocks aren't visible to the contract system        
5551         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5552         return m_pCallback2->RemotingServerReceivingMessage(pCookie, fIsAsync);
5553     }
5554 }
5555
5556 HRESULT EEToProfInterfaceImpl::RemotingServerInvocationStarted()
5557 {
5558     CONTRACTL
5559     {
5560         // Yay!
5561         NOTHROW;
5562
5563         // Yay!
5564         GC_TRIGGERS;
5565
5566         // Yay!
5567         MODE_PREEMPTIVE;
5568
5569         // Yay!
5570         CAN_TAKE_LOCK;
5571
5572         // Yay!
5573         ASSERT_NO_EE_LOCKS_HELD();
5574
5575     }
5576     CONTRACTL_END;
5577
5578     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5579                                 LL_INFO1000, 
5580                                 "**PROF: RemotingServerInvocationStarted. ThreadID: 0x%p\n", 
5581                                 GetThread()));
5582
5583     {
5584         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5585         // whose try/catch blocks aren't visible to the contract system        
5586         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5587         return m_pCallback2->RemotingServerInvocationStarted();
5588     }
5589 }
5590
5591 HRESULT EEToProfInterfaceImpl::RemotingServerInvocationReturned()
5592 {
5593     CONTRACTL
5594     {
5595         // Yay!
5596         NOTHROW;
5597
5598         // Yay!
5599         GC_TRIGGERS;
5600
5601         // Yay!
5602         MODE_PREEMPTIVE;
5603
5604         // Yay!
5605         CAN_TAKE_LOCK;
5606
5607         // Yay!
5608         ASSERT_NO_EE_LOCKS_HELD();
5609
5610     }
5611     CONTRACTL_END;
5612
5613     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5614                                 LL_INFO1000, 
5615                                 "**PROF: RemotingServerInvocationReturned. ThreadID: 0x%p\n", 
5616                                 GetThread()));
5617
5618     {
5619         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5620         // whose try/catch blocks aren't visible to the contract system        
5621         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5622         return m_pCallback2->RemotingServerInvocationReturned();
5623     }
5624 }
5625
5626 HRESULT EEToProfInterfaceImpl::RemotingServerSendingReply(GUID *pCookie, BOOL fIsAsync)
5627 {
5628     CONTRACTL
5629     {
5630         // Yay!
5631         NOTHROW;
5632
5633         // Yay!
5634         GC_TRIGGERS;
5635
5636         // Yay!
5637         MODE_PREEMPTIVE;
5638
5639         // Yay!
5640         CAN_TAKE_LOCK;
5641
5642         // Yay!
5643         ASSERT_NO_EE_LOCKS_HELD();
5644
5645     }
5646     CONTRACTL_END;
5647
5648     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5649                                 LL_INFO1000, 
5650                                 "**PROF: RemotingServerSendingReply. ThreadID: 0x%p\n", 
5651                                 GetThread()));
5652
5653     {
5654         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5655         // whose try/catch blocks aren't visible to the contract system        
5656         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5657         return m_pCallback2->RemotingServerSendingReply(pCookie, fIsAsync);
5658     }
5659 }
5660
5661 //---------------------------------------------------------------------------------------
5662 // GC EVENTS
5663 //
5664
5665 HRESULT EEToProfInterfaceImpl::ObjectAllocated(
5666     /* [in] */ ObjectID objectId,
5667     /* [in] */ ClassID classId)
5668 {
5669     CONTRACTL
5670     {
5671         // Yay!
5672         NOTHROW;
5673
5674         // Yay!
5675         GC_TRIGGERS;
5676
5677         // Preemptive mode would be bad, dude.  There's an objectId in the param list!
5678         MODE_COOPERATIVE;
5679
5680         // Yay!
5681         CAN_TAKE_LOCK;
5682
5683         // CrstAppDomainHandleTable can be held while this is called
5684
5685     }
5686     CONTRACTL_END;
5687     
5688     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5689                                 LL_INFO1000, 
5690                                 "**PROF: ObjectAllocated. ObjectID: 0x%p.  ClassID: 0x%p\n", 
5691                                 objectId, 
5692                                 classId));
5693
5694     {
5695         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5696         // whose try/catch blocks aren't visible to the contract system        
5697         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5698         return m_pCallback2->ObjectAllocated(objectId, classId);
5699     }
5700 }
5701
5702
5703 HRESULT EEToProfInterfaceImpl::MovedReferences(GCReferencesData *pData)
5704 {
5705     CONTRACTL
5706     {
5707         // Yay!
5708         NOTHROW;
5709
5710         // This is called by the thread doing a GC WHILE it does the GC
5711         GC_NOTRIGGER;
5712
5713         // This is called by the thread doing a GC WHILE it does the GC
5714         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
5715
5716         // Yay!
5717         CAN_TAKE_LOCK;
5718
5719         // Thread store lock normally held during this callback
5720
5721     }
5722     CONTRACTL_END;
5723
5724     CLR_TO_PROFILER_ENTRYPOINT_EX(
5725         kEE2PNoTrigger,
5726         (LF_CORPROF, 
5727         LL_INFO10000, 
5728         "**PROF: MovedReferences.\n"));
5729
5730     _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5731     
5732     if (pData->curIdx == 0)
5733     {
5734         return S_OK;
5735     }
5736
5737     HRESULT hr = S_OK;
5738
5739     if (pData->compactingCount != 0)
5740     {
5741         _ASSERTE(pData->curIdx == pData->compactingCount);
5742
5743         if (m_pCallback4 != NULL)
5744         {
5745             // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5746             // whose try/catch blocks aren't visible to the contract system        
5747             PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5748             hr = m_pCallback4->MovedReferences2((ULONG)pData->curIdx,
5749                                                 (ObjectID *)pData->arrpbMemBlockStartOld,
5750                                                 (ObjectID *)pData->arrpbMemBlockStartNew,
5751                                                 (SIZE_T *)pData->arrMemBlockSize);
5752             if (FAILED(hr))
5753                 return hr;
5754         }
5755
5756 #ifdef _WIN64
5757         // Recompute sizes as ULONGs for legacy callback
5758         for (ULONG i = 0; i < pData->curIdx; i++)
5759             pData->arrULONG[i] = (pData->arrMemBlockSize[i] > ULONG_MAX) ? ULONG_MAX : (ULONG)pData->arrMemBlockSize[i];
5760 #endif
5761
5762         {
5763             // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5764             // whose try/catch blocks aren't visible to the contract system        
5765             PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5766             hr = m_pCallback2->MovedReferences((ULONG)pData->curIdx,
5767                                                (ObjectID *)pData->arrpbMemBlockStartOld,
5768                                                (ObjectID *)pData->arrpbMemBlockStartNew,
5769                                                pData->arrULONG);
5770         }
5771     }
5772     else
5773     {
5774         if (m_pCallback4 != NULL)
5775         {
5776             // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5777             // whose try/catch blocks aren't visible to the contract system        
5778             PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5779             hr = m_pCallback4->SurvivingReferences2((ULONG)pData->curIdx,
5780                                                     (ObjectID *)pData->arrpbMemBlockStartOld,
5781                                                     (SIZE_T *)pData->arrMemBlockSize);
5782             if (FAILED(hr))
5783                 return hr;
5784         }
5785
5786 #ifdef _WIN64
5787         // Recompute sizes as ULONGs for legacy callback
5788         for (ULONG i = 0; i < pData->curIdx; i++)
5789             pData->arrULONG[i] = (pData->arrMemBlockSize[i] > ULONG_MAX) ? ULONG_MAX : (ULONG)pData->arrMemBlockSize[i];
5790 #endif
5791
5792         {
5793             // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5794             // whose try/catch blocks aren't visible to the contract system        
5795             PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5796             hr = m_pCallback2->SurvivingReferences((ULONG)pData->curIdx,
5797                                                    (ObjectID *)pData->arrpbMemBlockStartOld,
5798                                                    pData->arrULONG);
5799         }
5800     }
5801
5802     return hr;
5803 }
5804
5805 HRESULT EEToProfInterfaceImpl::NotifyAllocByClass(AllocByClassData *pData)
5806 {
5807     CONTRACTL
5808     {
5809         // Yay!
5810         NOTHROW;
5811
5812         // This is called by the thread doing a GC WHILE it does the GC
5813         GC_NOTRIGGER;
5814
5815         // This is called by the thread doing a GC WHILE it does the GC
5816         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
5817
5818         // Yay!
5819         CAN_TAKE_LOCK;
5820
5821         // Thread store lock normally held during this callback
5822
5823     }
5824     CONTRACTL_END;
5825     
5826     CLR_TO_PROFILER_ENTRYPOINT_EX(
5827         kEE2PNoTrigger,
5828         (LF_CORPROF, 
5829         LL_INFO10000, 
5830         "**PROF: ObjectsAllocatedByClass.\n"));
5831
5832     _ASSERTE(pData != NULL);
5833     _ASSERTE(pData->iHash > 0);
5834
5835     // If the arrays are not long enough, get rid of them.
5836     if (pData->cLength != 0 && pData->iHash > pData->cLength)
5837     {
5838         _ASSERTE(pData->arrClsId != NULL && pData->arrcObjects != NULL);
5839         delete [] pData->arrClsId;
5840         delete [] pData->arrcObjects;
5841         pData->cLength = 0;
5842     }
5843
5844     // If there are no arrays, must allocate them.
5845     if (pData->cLength == 0)
5846     {
5847         pData->arrClsId = new (nothrow) ClassID[pData->iHash];
5848         if (pData->arrClsId == NULL)
5849         {
5850             return E_OUTOFMEMORY;
5851         }
5852
5853         pData->arrcObjects = new (nothrow) ULONG[pData->iHash];
5854         if (pData->arrcObjects == NULL)
5855         {
5856             delete [] pData->arrClsId;
5857             pData->arrClsId= NULL;
5858
5859             return E_OUTOFMEMORY;
5860         }
5861
5862         // Indicate that the memory was successfully allocated
5863         pData->cLength = pData->iHash;
5864     }
5865
5866     // Now copy all the data
5867     HASHFIND hFind;
5868     CLASSHASHENTRY * pCur = (CLASSHASHENTRY *) pData->pHashTable->FindFirstEntry(&hFind);
5869     size_t iCur = 0;    // current index for arrays
5870
5871     while (pCur != NULL)
5872     {
5873         _ASSERTE(iCur < pData->iHash);
5874
5875         pData->arrClsId[iCur] = pCur->m_clsId;
5876         pData->arrcObjects[iCur] = (DWORD) pCur->m_count;
5877
5878         // Move to the next entry
5879         iCur++;
5880         pCur = (CLASSHASHENTRY *) pData->pHashTable->FindNextEntry(&hFind);
5881     }
5882
5883     _ASSERTE(iCur == pData->iHash);
5884
5885     // Now communicate the results to the profiler
5886     {
5887         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5888         // whose try/catch blocks aren't visible to the contract system        
5889         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5890         return m_pCallback2->ObjectsAllocatedByClass((ULONG)pData->iHash, pData->arrClsId, pData->arrcObjects);
5891     }
5892 }
5893
5894 HRESULT EEToProfInterfaceImpl::ObjectReference(ObjectID objId,
5895                                                ClassID classId,
5896                                                ULONG cNumRefs,
5897                                                ObjectID *arrObjRef)
5898 {
5899     CONTRACTL
5900     {
5901         // Yay!
5902         NOTHROW;
5903
5904         // This is called by the thread doing a GC WHILE it does the GC
5905         GC_NOTRIGGER;
5906
5907         // This is called by the thread doing a GC WHILE it does the GC
5908         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
5909
5910         // Yay!
5911         CAN_TAKE_LOCK;
5912
5913         // Thread store lock normally held during this callback
5914
5915     }
5916     CONTRACTL_END;
5917     
5918     CLR_TO_PROFILER_ENTRYPOINT_EX(
5919         kEE2PNoTrigger,
5920         (LF_CORPROF, 
5921         LL_INFO100000, 
5922         "**PROF: ObjectReferences.\n"));
5923
5924     _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5925     
5926     {                
5927         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5928         // whose try/catch blocks aren't visible to the contract system        
5929         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5930         return m_pCallback2->ObjectReferences(objId, classId, cNumRefs, arrObjRef);
5931     }
5932 }
5933
5934
5935 HRESULT EEToProfInterfaceImpl::FinalizeableObjectQueued(BOOL isCritical, ObjectID objectID)
5936 {
5937     CONTRACTL
5938     {
5939         // Yay!
5940         NOTHROW;
5941
5942         // Yay!
5943         GC_TRIGGERS;
5944
5945         // Can't be in preemptive when we're dealing in objectIDs!
5946         // However, it's possible we're on a non-EE Thread--that happens when this
5947         // is a server-mode GC thread.
5948         MODE_COOPERATIVE;
5949
5950         // Yay!
5951         CAN_TAKE_LOCK;
5952
5953         // Thread store lock normally held during this callback
5954
5955     }
5956     CONTRACTL_END;
5957
5958     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
5959                                 LL_INFO100, 
5960                                 "**PROF: Notifying profiler of finalizeable object.\n"));
5961
5962     _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5963     
5964     {                
5965         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5966         // whose try/catch blocks aren't visible to the contract system        
5967         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5968         return m_pCallback2->FinalizeableObjectQueued(isCritical ? COR_PRF_FINALIZER_CRITICAL : 0, objectID);
5969     }
5970 }
5971
5972
5973 HRESULT EEToProfInterfaceImpl::RootReferences2(GCReferencesData *pData)
5974 {
5975     CONTRACTL
5976     {
5977         // Yay!
5978         NOTHROW;
5979
5980         // This is called by the thread doing a GC WHILE it does the GC
5981         GC_NOTRIGGER;
5982
5983         // This is called by the thread doing a GC WHILE it does the GC
5984         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
5985
5986         // Yay!
5987         CAN_TAKE_LOCK;
5988
5989         // Thread store lock normally held during this callback
5990
5991     }
5992     CONTRACTL_END;
5993     
5994     CLR_TO_PROFILER_ENTRYPOINT_EX(
5995         kEE2PNoTrigger,
5996         (LF_CORPROF, 
5997         LL_INFO10000, 
5998         "**PROF: RootReferences2.\n"));
5999
6000     _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6001     
6002     HRESULT hr = S_OK;
6003
6004     COR_PRF_GC_ROOT_FLAGS flags[kcReferencesMax];
6005
6006     _ASSERTE(pData->curIdx <= kcReferencesMax);
6007     for (ULONG i = 0; i < pData->curIdx; i++)
6008     {
6009         flags[i] = (COR_PRF_GC_ROOT_FLAGS)(pData->arrULONG[i] & 0xffff);
6010         pData->arrULONG[i] >>= 16;
6011     }
6012
6013     {
6014         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6015         // whose try/catch blocks aren't visible to the contract system        
6016         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6017         hr = m_pCallback2->RootReferences2((ULONG)pData->curIdx,
6018                                           (ObjectID *)pData->arrpbMemBlockStartOld,
6019                                           (COR_PRF_GC_ROOT_KIND *)pData->arrULONG,
6020                                           flags,
6021                                           (ObjectID *)pData->arrpbMemBlockStartNew);
6022         if (FAILED(hr))
6023             return hr;
6024     }
6025
6026     {
6027         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6028         // whose try/catch blocks aren't visible to the contract system        
6029         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6030         hr = m_pCallback2->RootReferences((ULONG)pData->curIdx, (ObjectID *)pData->arrpbMemBlockStartOld);
6031     }
6032
6033     return hr;
6034 }
6035
6036
6037 HRESULT EEToProfInterfaceImpl::ConditionalWeakTableElementReferences(GCReferencesData * pData)
6038 {
6039     CONTRACTL
6040     {
6041         // Yay!
6042         NOTHROW;
6043
6044         // This is called by the thread doing a GC WHILE it does the GC
6045         GC_NOTRIGGER;
6046
6047         // This is called by the thread doing a GC WHILE it does the GC
6048         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
6049
6050         // Yay!
6051         CAN_TAKE_LOCK;
6052
6053         // Thread store lock normally held during this callback
6054
6055     }
6056     CONTRACTL_END;
6057     
6058     CLR_TO_PROFILER_ENTRYPOINT_EX(
6059         kEE2PNoTrigger,
6060         (LF_CORPROF, 
6061         LL_INFO10000, 
6062         "**PROF: ConditionalWeakTableElementReferences.\n"));
6063
6064     _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6065     
6066     HRESULT hr = S_OK;
6067
6068     _ASSERTE(pData->curIdx <= kcReferencesMax);
6069
6070     {
6071         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6072         // whose try/catch blocks aren't visible to the contract system        
6073         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6074         hr = m_pCallback5->ConditionalWeakTableElementReferences(
6075                                           (ULONG)pData->curIdx,
6076                                           (ObjectID *)pData->arrpbMemBlockStartOld,
6077                                           (ObjectID *)pData->arrpbMemBlockStartNew,
6078                                           (GCHandleID *)pData->arrpbRootId);
6079     }
6080
6081     return hr;
6082 }
6083
6084 HRESULT EEToProfInterfaceImpl::HandleCreated(UINT_PTR handleId, ObjectID initialObjectId)
6085 {
6086     CONTRACTL
6087     {
6088         // Yay!
6089         NOTHROW;
6090
6091         // Called by HndCreateHandle which is notrigger
6092         GC_NOTRIGGER;
6093
6094         // This can be called in preemptive mode if initialObjectId is NULL.
6095         // Otherwise, this will be in cooperative mode.  Note that, although this
6096         // can be called in preemptive, when it's called in cooperative we must not
6097         // switch to preemptive (as we normally do in callbacks) and must not trigger,
6098         // as this would really tick off some of our callers (as well as invalidating
6099         // initialObjectId).
6100         if (initialObjectId != NULL) 
6101         { 
6102             MODE_COOPERATIVE; 
6103         }
6104         else
6105         {
6106             MODE_ANY;
6107         }
6108
6109         // Yay!
6110         CAN_TAKE_LOCK;
6111
6112         // CrstAppDomainHandleTable can be held during this callback
6113
6114     }
6115     CONTRACTL_END;
6116
6117     CLR_TO_PROFILER_ENTRYPOINT_EX(
6118         kEE2PNoTrigger,
6119         (LF_CORPROF, 
6120         LL_INFO10000, 
6121         "**PROF: HandleCreated.\n"));
6122
6123     {
6124         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6125         // whose try/catch blocks aren't visible to the contract system        
6126         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6127         return m_pCallback2->HandleCreated(handleId, initialObjectId);
6128     }
6129 }
6130
6131 HRESULT EEToProfInterfaceImpl::HandleDestroyed(UINT_PTR handleId)
6132 {
6133     CONTRACTL
6134     {
6135         // Yay!
6136         NOTHROW;
6137
6138         // Called by HndDestroyHandle, which is notrigger.  But HndDestroyHandle is also 
6139         // MODE_ANY, so perhaps we can change the whole call path to be triggers?
6140         GC_NOTRIGGER;
6141
6142         // Although we're called from a notrigger function, I verified empirically that 
6143         // this is called coop & preemp
6144         MODE_ANY;
6145
6146         // Yay!
6147         CAN_TAKE_LOCK;
6148
6149         // Thread store lock is typically held during this callback
6150
6151     }
6152     CONTRACTL_END;
6153
6154     CLR_TO_PROFILER_ENTRYPOINT_EX(
6155         kEE2PNoTrigger,
6156         (LF_CORPROF, 
6157         LL_INFO10000, 
6158         "**PROF: HandleDestroyed.\n"));
6159
6160     {
6161         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6162         // whose try/catch blocks aren't visible to the contract system        
6163         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6164         return m_pCallback2->HandleDestroyed(handleId);
6165     }
6166 }
6167
6168 HRESULT EEToProfInterfaceImpl::GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason)
6169 {
6170     CONTRACTL
6171     {
6172         // Yay!
6173         NOTHROW;
6174
6175         // This is called by the thread doing a GC WHILE it does the GC
6176         GC_NOTRIGGER;
6177
6178         // This is called by the thread doing a GC WHILE it does the GC
6179         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
6180
6181         // Yay!
6182         CAN_TAKE_LOCK;
6183
6184         // Thread store lock normally held during this callback
6185
6186     }
6187     CONTRACTL_END;
6188     
6189     CLR_TO_PROFILER_ENTRYPOINT_EX(
6190         kEE2PNoTrigger,
6191         (LF_CORPROF, 
6192         LL_INFO10000, 
6193         "**PROF: GarbageCollectionStarted.\n"));
6194
6195     _ASSERTE(!CORProfilerTrackGC() || !GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6196     
6197     {            
6198         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6199         // whose try/catch blocks aren't visible to the contract system        
6200         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6201         return m_pCallback2->GarbageCollectionStarted(cGenerations, generationCollected, reason);
6202     }
6203 }
6204
6205 HRESULT EEToProfInterfaceImpl::GarbageCollectionFinished()
6206 {
6207     CONTRACTL
6208     {
6209         // Yay!
6210         NOTHROW;
6211
6212         // This is called by the thread doing a GC WHILE it does the GC
6213         GC_NOTRIGGER;
6214
6215         // This is called by the thread doing a GC WHILE it does the GC
6216         if (GetThreadNULLOk()) { MODE_COOPERATIVE; } 
6217
6218         // Yay!
6219         CAN_TAKE_LOCK;
6220
6221         // Thread store lock normally held during this callback
6222
6223     }
6224     CONTRACTL_END;
6225     
6226     CLR_TO_PROFILER_ENTRYPOINT_EX(
6227         kEE2PNoTrigger,
6228         (LF_CORPROF, 
6229         LL_INFO10000, 
6230         "**PROF: GarbageCollectionFinished.\n"));
6231
6232     _ASSERTE(!CORProfilerTrackGC() || !GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6233     
6234     {        
6235         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6236         // whose try/catch blocks aren't visible to the contract system        
6237         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6238         return m_pCallback2->GarbageCollectionFinished();
6239     }
6240 }
6241
6242 HRESULT EEToProfInterfaceImpl::ProfilerDetachSucceeded()
6243 {
6244     CONTRACTL
6245     {
6246         // Yay!
6247         NOTHROW;
6248
6249         // Yay!
6250         GC_TRIGGERS;
6251
6252         // Yay!
6253         MODE_PREEMPTIVE;
6254
6255         // Yay!
6256         CAN_TAKE_LOCK;
6257
6258         // ProfilingAPIUtility::s_csStatus is held while this callback is issued.
6259         
6260     }
6261     CONTRACTL_END;
6262     
6263     CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileDetaching,
6264         (LF_CORPROF, 
6265          LL_INFO10, 
6266          "**PROF: ProfilerDetachSucceeded.\n"));
6267
6268     // Should only be called on profilers that support ICorProfilerCallback3
6269     _ASSERTE(m_pCallback3 != NULL);
6270
6271     {
6272         // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6273         // whose try/catch blocks aren't visible to the contract system        
6274         PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6275         return m_pCallback3->ProfilerDetachSucceeded();
6276     }
6277 }
6278
6279
6280
6281 HRESULT EEToProfInterfaceImpl::GetAssemblyReferences(LPCWSTR wszAssemblyPath, IAssemblyBindingClosure * pClosure, AssemblyReferenceClosureWalkContextForProfAPI * pContext)
6282 {
6283     CONTRACTL
6284     {
6285         // Yay!
6286         NOTHROW;
6287
6288         // Yay!
6289         GC_TRIGGERS;
6290
6291         // Yay!
6292         MODE_PREEMPTIVE;
6293
6294         // Yay!
6295         CAN_TAKE_LOCK;
6296
6297     }
6298     CONTRACTL_END;
6299     
6300     CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, 
6301                                 LL_INFO10, 
6302                                 "**PROF: AssemblyReferenceClosureWalkStarted.  wszAssemblyPath: 0x%p.\n", 
6303                                 wszAssemblyPath
6304                                 ));
6305     HRESULT hr = S_OK;
6306
6307
6308     return hr;
6309 }
6310
6311
6312 #endif // PROFILING_SUPPORTED