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