1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // EEToProfInterfaceImpl.h
9 // Declaration of class that wraps calling into the profiler's implementation
10 // of ICorProfilerCallback*
13 // ======================================================================================
16 #ifndef __EETOPROFINTERFACEIMPL_H__
17 #define __EETOPROFINTERFACEIMPL_H__
20 #include "profilepriv.h"
21 #include "eeprofinterfaces.h"
23 #include "eventtracebase.h"
27 class ProfToEEInterfaceImpl;
29 interface IAssemblyBindingClosure;
30 struct AssemblyReferenceClosureWalkContextForProfAPI;
32 const GUID k_guidZero = {0};
34 class EEToProfInterfaceImpl
39 // Internal initialization / cleanup
42 EEToProfInterfaceImpl();
43 ~EEToProfInterfaceImpl();
46 ProfToEEInterfaceImpl * pProfToEE,
48 __inout_z LPCWSTR wszClsid,
49 __in_z LPCWSTR wszProfileDLL,
50 BOOL fLoadedViaAttach,
51 DWORD dwConcurrentGCWaitTimeoutInMs);
53 BOOL IsCallback3Supported();
54 BOOL IsCallback4Supported();
55 BOOL IsCallback5Supported();
56 BOOL IsCallback6Supported();
57 BOOL IsCallback7Supported();
58 BOOL IsCallback8Supported();
60 HRESULT SetEventMask(DWORD dwEventMask, DWORD dwEventMaskHigh);
62 // Used in ProfToEEInterfaceImpl.cpp to set this to the profiler's hook's
63 // function pointer (see SetFunctionIDMapper).
64 void SetFunctionIDMapper(FunctionIDMapper * pFunc);
65 void SetFunctionIDMapper2(FunctionIDMapper2 * pFunc, void * clientData);
67 FunctionIDMapper * GetFunctionIDMapper();
68 FunctionIDMapper2 * GetFunctionIDMapper2();
69 BOOL IsLoadedViaAttach();
70 HRESULT EnsureProfilerDetachable();
71 void SetUnrevertiblyModifiedILFlag();
73 FunctionEnter * GetEnterHook();
74 FunctionLeave * GetLeaveHook();
75 FunctionTailcall * GetTailcallHook();
77 FunctionEnter2 * GetEnter2Hook();
78 FunctionLeave2 * GetLeave2Hook();
79 FunctionTailcall2 * GetTailcall2Hook();
81 FunctionEnter3 * GetEnter3Hook();
82 FunctionLeave3 * GetLeave3Hook();
83 FunctionTailcall3 * GetTailcall3Hook();
84 FunctionEnter3WithInfo * GetEnter3WithInfoHook();
85 FunctionLeave3WithInfo * GetLeave3WithInfoHook();
86 FunctionTailcall3WithInfo * GetTailcall3WithInfoHook();
88 BOOL IsClientIDToFunctionIDMappingEnabled();
90 UINT_PTR LookupClientIDFromCache(FunctionID functionID);
92 HRESULT SetEnterLeaveFunctionHooks(
93 FunctionEnter * pFuncEnter,
94 FunctionLeave * pFuncLeave,
95 FunctionTailcall * pFuncTailcall);
97 HRESULT SetEnterLeaveFunctionHooks2(
98 FunctionEnter2 * pFuncEnter,
99 FunctionLeave2 * pFuncLeave,
100 FunctionTailcall2 * pFuncTailcall);
102 HRESULT SetEnterLeaveFunctionHooks3(
103 FunctionEnter3 * pFuncEnter3,
104 FunctionLeave3 * pFuncLeave3,
105 FunctionTailcall3 * pFuncTailcall3);
107 HRESULT SetEnterLeaveFunctionHooks3WithInfo(
108 FunctionEnter3WithInfo * pFuncEnter3WithInfo,
109 FunctionLeave3WithInfo * pFuncLeave3WithInfo,
110 FunctionTailcall3WithInfo * pFuncTailcall3WithInfo);
112 BOOL RequiresGenericsContextForEnterLeave();
114 UINT_PTR EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction);
116 // This fills in the non call-specific portions of the cookie GUID.
117 // This should only be called once at startup if necessary.
120 // This will assign a mostly-unique GUID. If enough calls to GetGUID
121 // are made from the same thread, then the GUIDs will cycle.
122 // (Current, it will cycle every 256 calls)
123 void GetGUID(GUID * pGUID);
126 // Initialize callback
129 HRESULT Initialize();
131 HRESULT InitializeForAttach(void * pvClientData, UINT cbClientData);
133 HRESULT ProfilerAttachComplete();
139 HRESULT ThreadCreated(
142 HRESULT ThreadDestroyed(
145 HRESULT ThreadAssignedToOSThread(ThreadID managedThreadId,
148 HRESULT ThreadNameChanged(ThreadID managedThreadId,
150 __in_ecount_opt(cchName) WCHAR name[]);
153 // Startup/Shutdown Events
159 // JIT/Function Events
162 HRESULT FunctionUnloadStarted(
163 FunctionID functionId);
165 HRESULT JITCompilationFinished(
166 FunctionID functionId,
168 BOOL fIsSafeToBlock);
170 HRESULT JITCompilationStarted(
171 FunctionID functionId,
172 BOOL fIsSafeToBlock);
174 HRESULT DynamicMethodJITCompilationStarted(
175 FunctionID functionId,
178 HRESULT DynamicMethodJITCompilationFinished(
179 FunctionID functionId);
181 HRESULT JITCachedFunctionSearchStarted(
182 /* [in] */ FunctionID functionId,
183 /* [out] */ BOOL * pbUseCachedFunction);
185 HRESULT JITCachedFunctionSearchFinished(
186 /* [in] */ FunctionID functionId,
187 /* [in] */ COR_PRF_JIT_CACHE result);
189 HRESULT JITFunctionPitched(FunctionID functionId);
192 /* [in] */ FunctionID callerId,
193 /* [in] */ FunctionID calleeId,
194 /* [out] */ BOOL * pfShouldInline);
196 HRESULT ReJITCompilationStarted(
197 /* [in] */ FunctionID functionId,
198 /* [in] */ ReJITID reJitId,
199 /* [in] */ BOOL fIsSafeToBlock);
201 HRESULT GetReJITParameters(
202 /* [in] */ ModuleID moduleId,
203 /* [in] */ mdMethodDef methodId,
204 /* [in] */ ICorProfilerFunctionControl *
207 HRESULT ReJITCompilationFinished(
208 /* [in] */ FunctionID functionId,
209 /* [in] */ ReJITID reJitId,
210 /* [in] */ HRESULT hrStatus,
211 /* [in] */ BOOL fIsSafeToBlock);
214 /* [in] */ ModuleID moduleId,
215 /* [in] */ mdMethodDef methodId,
216 /* [in] */ FunctionID functionId,
217 /* [in] */ HRESULT hrStatus);
223 HRESULT ModuleLoadStarted(
226 HRESULT ModuleLoadFinished(
230 HRESULT ModuleUnloadStarted(
233 HRESULT ModuleUnloadFinished(
237 HRESULT ModuleAttachedToAssembly(
239 AssemblyID AssemblyId);
241 HRESULT ModuleInMemorySymbolsUpdated(
248 HRESULT ClassLoadStarted(
251 HRESULT ClassLoadFinished(
255 HRESULT ClassUnloadStarted(
258 HRESULT ClassUnloadFinished(
266 HRESULT AppDomainCreationStarted(
267 AppDomainID appDomainId);
269 HRESULT AppDomainCreationFinished(
270 AppDomainID appDomainId,
273 HRESULT AppDomainShutdownStarted(
274 AppDomainID appDomainId);
276 HRESULT AppDomainShutdownFinished(
277 AppDomainID appDomainId,
284 HRESULT AssemblyLoadStarted(
285 AssemblyID assemblyId);
287 HRESULT AssemblyLoadFinished(
288 AssemblyID assemblyId,
291 HRESULT AssemblyUnloadStarted(
292 AssemblyID assemblyId);
294 HRESULT AssemblyUnloadFinished(
295 AssemblyID assemblyId,
302 HRESULT UnmanagedToManagedTransition(
303 FunctionID functionId,
304 COR_PRF_TRANSITION_REASON reason);
306 HRESULT ManagedToUnmanagedTransition(
307 FunctionID functionId,
308 COR_PRF_TRANSITION_REASON reason);
314 HRESULT ExceptionThrown(
315 ObjectID thrownObjectId);
317 HRESULT ExceptionSearchFunctionEnter(
318 FunctionID functionId);
320 HRESULT ExceptionSearchFunctionLeave();
322 HRESULT ExceptionSearchFilterEnter(
325 HRESULT ExceptionSearchFilterLeave();
327 HRESULT ExceptionSearchCatcherFound(
328 FunctionID functionId);
330 HRESULT ExceptionOSHandlerEnter(
333 HRESULT ExceptionOSHandlerLeave(
336 HRESULT ExceptionUnwindFunctionEnter(
337 FunctionID functionId);
339 HRESULT ExceptionUnwindFunctionLeave();
341 HRESULT ExceptionUnwindFinallyEnter(
342 FunctionID functionId);
344 HRESULT ExceptionUnwindFinallyLeave();
346 HRESULT ExceptionCatcherEnter(
347 FunctionID functionId,
350 HRESULT ExceptionCatcherLeave();
356 HRESULT COMClassicVTableCreated(
357 /* [in] */ ClassID wrappedClassId,
358 /* [in] */ REFGUID implementedIID,
359 /* [in] */ void * pVTable,
360 /* [in] */ ULONG cSlots);
362 HRESULT COMClassicVTableDestroyed(
363 /* [in] */ ClassID wrappedClassId,
364 /* [in] */ REFGUID implementedIID,
365 /* [in] */ void * pVTable);
371 HRESULT RemotingClientInvocationStarted();
373 HRESULT RemotingClientSendingMessage(GUID * pCookie,
376 HRESULT RemotingClientReceivingReply(GUID * pCookie,
379 HRESULT RemotingClientInvocationFinished();
381 HRESULT RemotingServerReceivingMessage(GUID * pCookie,
384 HRESULT RemotingServerInvocationStarted();
386 HRESULT RemotingServerInvocationReturned();
388 HRESULT RemotingServerSendingReply(GUID * pCookie,
396 HRESULT RuntimeSuspendStarted(COR_PRF_SUSPEND_REASON suspendReason);
398 HRESULT RuntimeSuspendFinished();
400 HRESULT RuntimeSuspendAborted();
402 HRESULT RuntimeResumeStarted();
404 HRESULT RuntimeResumeFinished();
406 HRESULT RuntimeThreadSuspended(ThreadID suspendedThreadId);
408 HRESULT RuntimeThreadResumed(ThreadID resumedThreadId);
410 HRESULT ObjectAllocated(
411 /* [in] */ ObjectID objectId,
412 /* [in] */ ClassID classId);
414 HRESULT FinalizeableObjectQueued(BOOL isCritical, ObjectID objectID);
417 // GC Moved References and RootReferences2 Notification Stuff
420 HRESULT MovedReference(BYTE * pbMemBlockStart,
421 BYTE * pbMemBlockEnd,
422 ptrdiff_t cbRelocDistance,
426 HRESULT EndMovedReferences(void * pHeapId);
428 HRESULT RootReference2(BYTE * objectId,
429 EtwGCRootKind dwEtwRootKind,
430 EtwGCRootFlags dwEtwRootFlags,
434 HRESULT EndRootReferences2(void * pHeapId);
436 HRESULT ConditionalWeakTableElementReference(BYTE * primaryObjectId,
437 BYTE * secondaryObjectId,
441 HRESULT EndConditionalWeakTableElementReferences(void * pHeapId);
444 // GC Root notification stuff
447 HRESULT AllocByClass(ObjectID objId, ClassID classId, void* pHeapId);
449 HRESULT EndAllocByClass(void * pHeapId);
452 // Heap walk notification stuff
454 HRESULT ObjectReference(ObjectID objId,
457 ObjectID * arrObjRef);
460 // GC Handle creation / destruction notifications
462 HRESULT HandleCreated(UINT_PTR handleId, ObjectID initialObjectId);
464 HRESULT HandleDestroyed(UINT_PTR handleId);
466 HRESULT GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason);
468 HRESULT GarbageCollectionFinished();
473 HRESULT ProfilerDetachSucceeded();
475 BOOL HasTimedOutWaitingForConcurrentGC();
477 HRESULT GetAssemblyReferences(LPCWSTR wszAssemblyPath, IAssemblyBindingClosure * pClosure, AssemblyReferenceClosureWalkContextForProfAPI * pContext);
482 // Generation 0 Allocation by Class notification stuff
485 // This is for a hashing of ClassID values
486 struct CLASSHASHENTRY : HASHENTRY
488 ClassID m_clsId; // The class ID (also the key)
489 size_t m_count; // How many of this class have been counted
492 // This is a simple implementation of CHashTable to provide a very simple
493 // implementation of the Cmp pure virtual function
494 class CHashTableImpl : public CHashTable
497 CHashTableImpl(ULONG iBuckets);
498 virtual ~CHashTableImpl();
501 virtual BOOL Cmp(SIZE_T k1, const HASHENTRY * pc2);
504 // This contains the data for storing allocation information
505 // in terms of numbers of objects sorted by class.
506 struct AllocByClassData
508 CHashTableImpl * pHashTable; // The hash table
509 CLASSHASHENTRY * arrHash; // Array that the hashtable uses for linking
510 ULONG cHash; // The total number of elements in arrHash
511 ULONG iHash; // Next empty entry in the hash array
512 ClassID * arrClsId; // Array of ClassIDs for the call to ObjectsAllocatedByClass
513 ULONG * arrcObjects; // Array of counts for the call to ObjectsAllocatedByClass
514 size_t cLength; // Length of the above two parallel arrays
517 static const UINT kcReferencesMax = 512;
519 struct GCReferencesData
522 size_t compactingCount;
523 BYTE * arrpbMemBlockStartOld[kcReferencesMax];
524 BYTE * arrpbMemBlockStartNew[kcReferencesMax];
527 size_t arrMemBlockSize[kcReferencesMax];
528 ULONG arrULONG[kcReferencesMax];
529 BYTE * arrpbRootId[kcReferencesMax];
531 GCReferencesData * pNext;
534 // Since this stuff can only be performed by one thread (right now), we don't need
535 // to make this thread safe and can just have one block we reuse every time around
536 static AllocByClassData * m_pSavedAllocDataBlock;
538 // Pointer to the profiler's implementation of the callback interface(s).
539 // Profilers MUST support ICorProfilerCallback2.
540 // Profilers MAY optionally support ICorProfilerCallback3,4,5,6,7,8
541 ICorProfilerCallback2 * m_pCallback2;
542 ICorProfilerCallback3 * m_pCallback3;
543 ICorProfilerCallback4 * m_pCallback4;
544 ICorProfilerCallback5 * m_pCallback5;
545 ICorProfilerCallback6 * m_pCallback6;
546 ICorProfilerCallback7 * m_pCallback7;
547 ICorProfilerCallback8 * m_pCallback8;
548 HMODULE m_hmodProfilerDLL;
550 BOOL m_fLoadedViaAttach;
551 ProfToEEInterfaceImpl * m_pProfToEE;
553 // Used in EEToProfInterfaceImpl.cpp to call into the profiler (see EEFunctionIDMapper)
554 FunctionIDMapper * m_pProfilersFuncIDMapper;
555 FunctionIDMapper2 * m_pProfilersFuncIDMapper2;
556 void * m_pProfilersFuncIDMapper2ClientData;
558 // This is used as a cookie template for remoting calls
561 // This is an incrementing counter for constructing unique GUIDS from
565 // This will contain a list of free ref data structs, so they
566 // don't have to be re-allocated on every GC
567 GCReferencesData * m_pGCRefDataFreeList;
569 // This is for managing access to the free list above.
570 CRITSEC_COOKIE m_csGCRefDataFreeList;
572 FunctionEnter * m_pEnter;
573 FunctionLeave * m_pLeave;
574 FunctionTailcall * m_pTailcall;
576 FunctionEnter2 * m_pEnter2;
577 FunctionLeave2 * m_pLeave2;
578 FunctionTailcall2 * m_pTailcall2;
580 BOOL m_fIsClientIDToFunctionIDMappingEnabled;
582 FunctionEnter3 * m_pEnter3;
583 FunctionLeave3 * m_pLeave3;
584 FunctionTailcall3 * m_pTailcall3;
586 FunctionEnter3WithInfo * m_pEnter3WithInfo;
587 FunctionLeave3WithInfo * m_pLeave3WithInfo;
588 FunctionTailcall3WithInfo * m_pTailcall3WithInfo;
591 // Remembers whether the profiler used SetILFunctionBody() which modifies IL in a
592 // way that cannot be reverted. This prevents a detach from succeeding.
593 BOOL m_fUnrevertiblyModifiedIL;
595 GCReferencesData * AllocateMovedReferencesData();
597 void FreeMovedReferencesData(GCReferencesData * pData);
599 HRESULT MovedReferences(GCReferencesData * pData);
601 HRESULT RootReferences2(GCReferencesData * pData);
603 HRESULT ConditionalWeakTableElementReferences(GCReferencesData * pData);
605 HRESULT NotifyAllocByClass(AllocByClassData * pData);
607 HRESULT CreateProfiler(
608 const CLSID * pClsid,
609 __in_z LPCWSTR wszClsid,
610 __in_z LPCWSTR wszProfileDLL);
612 HRESULT DetermineAndSetEnterLeaveFunctionHooksForJit();
614 HRESULT STDMETHODCALLTYPE SetEnterLeaveFunctionHooksForJit(
615 FunctionEnter3 * pFuncEnter,
616 FunctionLeave3 * pFuncLeave,
617 FunctionTailcall3 * pFuncTailcall);
619 struct FunctionIDAndClientID
621 FunctionID functionID;
625 class FunctionIDHashTableTraits : public NoRemoveSHashTraits<DefaultSHashTraits<FunctionIDAndClientID> >
629 static const COUNT_T s_minimum_allocation = 31;
630 typedef DefaultSHashTraits<FunctionIDAndClientID *>::count_t count_t;
631 typedef UINT_PTR key_t;
633 static key_t GetKey(FunctionIDAndClientID e)
635 LIMITED_METHOD_CONTRACT;
639 static BOOL Equals(key_t k1, key_t k2)
641 LIMITED_METHOD_CONTRACT;
645 static count_t Hash(key_t k)
647 LIMITED_METHOD_CONTRACT;
651 static const FunctionIDAndClientID Null()
653 LIMITED_METHOD_CONTRACT;
654 FunctionIDAndClientID functionIDAndClientID;
655 functionIDAndClientID.functionID = NULL;
656 functionIDAndClientID.clientID = NULL;
657 return functionIDAndClientID;
660 static bool IsNull(const FunctionIDAndClientID &functionIDAndClientID)
662 LIMITED_METHOD_CONTRACT;
663 _ASSERTE((functionIDAndClientID.functionID != NULL) || (functionIDAndClientID.clientID == NULL));
664 return functionIDAndClientID.functionID == NULL;
668 typedef SHash<FunctionIDHashTableTraits> FunctionIDHashTable;
670 // ELT3 no long keeps track of FunctionID of current managed method. Therefore, a hash table of bookkeeping
671 // the mapping from FunctionID to clientID is needed to build up ELT2 on top of ELT3. When ELT2 (slow-path
672 // or fast-path) is registered by the profiler and the profiler's IDFunctionMapper requests to hook up the
673 // function being loading, the clientID returned by FunctionIDMapper will be saved as the value to be looked
674 // up by the corresponding FunctionID in the hash table. FunctionIDs can be recycled after an app domain
675 // that contains the function bodies is unloaded so this hash table needs to replace the existing FunctionID
676 // with new FunctionID if a duplication is found in the hash table.
677 FunctionIDHashTable * m_pFunctionIDHashTable;
679 // Since the hash table can be read and writen concurrently, a reader-writer lock is used to synchronize
680 // all accesses to the hash table.
681 SimpleRWLock * m_pFunctionIDHashTableRWLock;
683 // Timeout for wait operation on concurrent GC. Only used for attach scenario
684 DWORD m_dwConcurrentGCWaitTimeoutInMs;
686 // Remember the fact we've timed out when waiting for concurrent GC. Will report the error later
687 BOOL m_bHasTimedOutWaitingForConcurrentGC;
690 #endif // __EETOPROFINTERFACEIMPL_H__