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