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.h |
6 | // |
7 | |
8 | // |
9 | // Declaration of class that wraps calling into the profiler's implementation |
10 | // of ICorProfilerCallback* |
11 | // |
12 | |
13 | // ====================================================================================== |
14 | |
15 | |
16 | #ifndef __EETOPROFINTERFACEIMPL_H__ |
17 | #define __EETOPROFINTERFACEIMPL_H__ |
18 | |
19 | #include <stddef.h> |
20 | #include "profilepriv.h" |
21 | #include "eeprofinterfaces.h" |
22 | #include "shash.h" |
23 | #include "eventtracebase.h" |
24 | #include "gcinterface.h" |
25 | |
26 | class SimpleRWLock; |
27 | |
28 | class ProfToEEInterfaceImpl; |
29 | |
30 | interface IAssemblyBindingClosure; |
31 | struct AssemblyReferenceClosureWalkContextForProfAPI; |
32 | |
33 | const GUID k_guidZero = {0}; |
34 | |
35 | class EEToProfInterfaceImpl |
36 | { |
37 | public: |
38 | |
39 | // |
40 | // Internal initialization / cleanup |
41 | // |
42 | |
43 | EEToProfInterfaceImpl(); |
44 | ~EEToProfInterfaceImpl(); |
45 | |
46 | HRESULT Init( |
47 | ProfToEEInterfaceImpl * pProfToEE, |
48 | const CLSID * pClsid, |
49 | __inout_z LPCWSTR wszClsid, |
50 | __in_z LPCWSTR wszProfileDLL, |
51 | BOOL fLoadedViaAttach, |
52 | DWORD dwConcurrentGCWaitTimeoutInMs); |
53 | |
54 | BOOL IsCallback3Supported(); |
55 | BOOL IsCallback4Supported(); |
56 | BOOL IsCallback5Supported(); |
57 | BOOL IsCallback6Supported(); |
58 | BOOL IsCallback7Supported(); |
59 | BOOL IsCallback8Supported(); |
60 | |
61 | HRESULT SetEventMask(DWORD dwEventMask, DWORD dwEventMaskHigh); |
62 | |
63 | // Used in ProfToEEInterfaceImpl.cpp to set this to the profiler's hook's |
64 | // function pointer (see SetFunctionIDMapper). |
65 | void SetFunctionIDMapper(FunctionIDMapper * pFunc); |
66 | void SetFunctionIDMapper2(FunctionIDMapper2 * pFunc, void * clientData); |
67 | |
68 | FunctionIDMapper * GetFunctionIDMapper(); |
69 | FunctionIDMapper2 * GetFunctionIDMapper2(); |
70 | BOOL IsLoadedViaAttach(); |
71 | HRESULT EnsureProfilerDetachable(); |
72 | void SetUnrevertiblyModifiedILFlag(); |
73 | void SetModifiedRejitState(); |
74 | |
75 | FunctionEnter * GetEnterHook(); |
76 | FunctionLeave * GetLeaveHook(); |
77 | FunctionTailcall * GetTailcallHook(); |
78 | |
79 | FunctionEnter2 * GetEnter2Hook(); |
80 | FunctionLeave2 * GetLeave2Hook(); |
81 | FunctionTailcall2 * GetTailcall2Hook(); |
82 | |
83 | FunctionEnter3 * GetEnter3Hook(); |
84 | FunctionLeave3 * GetLeave3Hook(); |
85 | FunctionTailcall3 * GetTailcall3Hook(); |
86 | FunctionEnter3WithInfo * GetEnter3WithInfoHook(); |
87 | FunctionLeave3WithInfo * GetLeave3WithInfoHook(); |
88 | FunctionTailcall3WithInfo * GetTailcall3WithInfoHook(); |
89 | |
90 | BOOL IsClientIDToFunctionIDMappingEnabled(); |
91 | |
92 | UINT_PTR LookupClientIDFromCache(FunctionID functionID); |
93 | |
94 | HRESULT SetEnterLeaveFunctionHooks( |
95 | FunctionEnter * pFuncEnter, |
96 | FunctionLeave * pFuncLeave, |
97 | FunctionTailcall * pFuncTailcall); |
98 | |
99 | HRESULT SetEnterLeaveFunctionHooks2( |
100 | FunctionEnter2 * pFuncEnter, |
101 | FunctionLeave2 * pFuncLeave, |
102 | FunctionTailcall2 * pFuncTailcall); |
103 | |
104 | HRESULT SetEnterLeaveFunctionHooks3( |
105 | FunctionEnter3 * pFuncEnter3, |
106 | FunctionLeave3 * pFuncLeave3, |
107 | FunctionTailcall3 * pFuncTailcall3); |
108 | |
109 | HRESULT SetEnterLeaveFunctionHooks3WithInfo( |
110 | FunctionEnter3WithInfo * pFuncEnter3WithInfo, |
111 | FunctionLeave3WithInfo * pFuncLeave3WithInfo, |
112 | FunctionTailcall3WithInfo * pFuncTailcall3WithInfo); |
113 | |
114 | BOOL RequiresGenericsContextForEnterLeave(); |
115 | |
116 | UINT_PTR EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction); |
117 | |
118 | // This fills in the non call-specific portions of the cookie GUID. |
119 | // This should only be called once at startup if necessary. |
120 | HRESULT InitGUID(); |
121 | |
122 | // This will assign a mostly-unique GUID. If enough calls to GetGUID |
123 | // are made from the same thread, then the GUIDs will cycle. |
124 | // (Current, it will cycle every 256 calls) |
125 | void GetGUID(GUID * pGUID); |
126 | |
127 | // |
128 | // Initialize callback |
129 | // |
130 | |
131 | HRESULT Initialize(); |
132 | |
133 | HRESULT InitializeForAttach(void * pvClientData, UINT cbClientData); |
134 | |
135 | HRESULT ProfilerAttachComplete(); |
136 | |
137 | // |
138 | // Thread Events |
139 | // |
140 | |
141 | HRESULT ThreadCreated( |
142 | ThreadID threadID); |
143 | |
144 | HRESULT ThreadDestroyed( |
145 | ThreadID threadID); |
146 | |
147 | HRESULT ThreadAssignedToOSThread(ThreadID managedThreadId, |
148 | DWORD osThreadId); |
149 | |
150 | HRESULT ThreadNameChanged(ThreadID managedThreadId, |
151 | ULONG cchName, |
152 | __in_ecount_opt(cchName) WCHAR name[]); |
153 | |
154 | // |
155 | // Startup/Shutdown Events |
156 | // |
157 | |
158 | HRESULT Shutdown(); |
159 | |
160 | // |
161 | // JIT/Function Events |
162 | // |
163 | |
164 | HRESULT FunctionUnloadStarted( |
165 | FunctionID functionId); |
166 | |
167 | HRESULT JITCompilationFinished( |
168 | FunctionID functionId, |
169 | HRESULT hrStatus, |
170 | BOOL fIsSafeToBlock); |
171 | |
172 | HRESULT JITCompilationStarted( |
173 | FunctionID functionId, |
174 | BOOL fIsSafeToBlock); |
175 | |
176 | HRESULT DynamicMethodJITCompilationStarted( |
177 | FunctionID functionId, |
178 | BOOL fIsSafeToBlock, |
179 | LPCBYTE , |
180 | ULONG ); |
181 | |
182 | HRESULT DynamicMethodJITCompilationFinished( |
183 | FunctionID functionId, |
184 | HRESULT hrStatus, |
185 | BOOL fIsSafeToBlock); |
186 | |
187 | HRESULT DynamicMethodUnloaded( |
188 | FunctionID functionId); |
189 | |
190 | HRESULT JITCachedFunctionSearchStarted( |
191 | /* [in] */ FunctionID functionId, |
192 | /* [out] */ BOOL * pbUseCachedFunction); |
193 | |
194 | HRESULT JITCachedFunctionSearchFinished( |
195 | /* [in] */ FunctionID functionId, |
196 | /* [in] */ COR_PRF_JIT_CACHE result); |
197 | |
198 | HRESULT JITFunctionPitched(FunctionID functionId); |
199 | |
200 | HRESULT JITInlining( |
201 | /* [in] */ FunctionID callerId, |
202 | /* [in] */ FunctionID calleeId, |
203 | /* [out] */ BOOL * pfShouldInline); |
204 | |
205 | HRESULT ReJITCompilationStarted( |
206 | /* [in] */ FunctionID functionId, |
207 | /* [in] */ ReJITID reJitId, |
208 | /* [in] */ BOOL fIsSafeToBlock); |
209 | |
210 | HRESULT GetReJITParameters( |
211 | /* [in] */ ModuleID moduleId, |
212 | /* [in] */ mdMethodDef methodId, |
213 | /* [in] */ ICorProfilerFunctionControl * |
214 | pFunctionControl); |
215 | |
216 | HRESULT ReJITCompilationFinished( |
217 | /* [in] */ FunctionID functionId, |
218 | /* [in] */ ReJITID reJitId, |
219 | /* [in] */ HRESULT hrStatus, |
220 | /* [in] */ BOOL fIsSafeToBlock); |
221 | |
222 | HRESULT ReJITError( |
223 | /* [in] */ ModuleID moduleId, |
224 | /* [in] */ mdMethodDef methodId, |
225 | /* [in] */ FunctionID functionId, |
226 | /* [in] */ HRESULT hrStatus); |
227 | |
228 | // |
229 | // Module Events |
230 | // |
231 | |
232 | HRESULT ModuleLoadStarted( |
233 | ModuleID moduleId); |
234 | |
235 | HRESULT ModuleLoadFinished( |
236 | ModuleID moduleId, |
237 | HRESULT hrStatus); |
238 | |
239 | HRESULT ModuleUnloadStarted( |
240 | ModuleID moduleId); |
241 | |
242 | HRESULT ModuleUnloadFinished( |
243 | ModuleID moduleId, |
244 | HRESULT hrStatus); |
245 | |
246 | HRESULT ModuleAttachedToAssembly( |
247 | ModuleID moduleId, |
248 | AssemblyID AssemblyId); |
249 | |
250 | HRESULT ModuleInMemorySymbolsUpdated( |
251 | ModuleID moduleId); |
252 | |
253 | // |
254 | // Class Events |
255 | // |
256 | |
257 | HRESULT ClassLoadStarted( |
258 | ClassID classId); |
259 | |
260 | HRESULT ClassLoadFinished( |
261 | ClassID classId, |
262 | HRESULT hrStatus); |
263 | |
264 | HRESULT ClassUnloadStarted( |
265 | ClassID classId); |
266 | |
267 | HRESULT ClassUnloadFinished( |
268 | ClassID classId, |
269 | HRESULT hrStatus); |
270 | |
271 | // |
272 | // AppDomain Events |
273 | // |
274 | |
275 | HRESULT AppDomainCreationStarted( |
276 | AppDomainID appDomainId); |
277 | |
278 | HRESULT AppDomainCreationFinished( |
279 | AppDomainID appDomainId, |
280 | HRESULT hrStatus); |
281 | |
282 | HRESULT AppDomainShutdownStarted( |
283 | AppDomainID appDomainId); |
284 | |
285 | HRESULT AppDomainShutdownFinished( |
286 | AppDomainID appDomainId, |
287 | HRESULT hrStatus); |
288 | |
289 | // |
290 | // Assembly Events |
291 | // |
292 | |
293 | HRESULT AssemblyLoadStarted( |
294 | AssemblyID assemblyId); |
295 | |
296 | HRESULT AssemblyLoadFinished( |
297 | AssemblyID assemblyId, |
298 | HRESULT hrStatus); |
299 | |
300 | HRESULT AssemblyUnloadStarted( |
301 | AssemblyID assemblyId); |
302 | |
303 | HRESULT AssemblyUnloadFinished( |
304 | AssemblyID assemblyId, |
305 | HRESULT hrStatus); |
306 | |
307 | // |
308 | // Transition Events |
309 | // |
310 | |
311 | HRESULT UnmanagedToManagedTransition( |
312 | FunctionID functionId, |
313 | COR_PRF_TRANSITION_REASON reason); |
314 | |
315 | HRESULT ManagedToUnmanagedTransition( |
316 | FunctionID functionId, |
317 | COR_PRF_TRANSITION_REASON reason); |
318 | |
319 | // |
320 | // Exception Events |
321 | // |
322 | |
323 | HRESULT ExceptionThrown( |
324 | ObjectID thrownObjectId); |
325 | |
326 | HRESULT ExceptionSearchFunctionEnter( |
327 | FunctionID functionId); |
328 | |
329 | HRESULT ExceptionSearchFunctionLeave(); |
330 | |
331 | HRESULT ExceptionSearchFilterEnter( |
332 | FunctionID funcId); |
333 | |
334 | HRESULT ExceptionSearchFilterLeave(); |
335 | |
336 | HRESULT ExceptionSearchCatcherFound( |
337 | FunctionID functionId); |
338 | |
339 | HRESULT ExceptionOSHandlerEnter( |
340 | FunctionID funcId); |
341 | |
342 | HRESULT ExceptionOSHandlerLeave( |
343 | FunctionID funcId); |
344 | |
345 | HRESULT ExceptionUnwindFunctionEnter( |
346 | FunctionID functionId); |
347 | |
348 | HRESULT ExceptionUnwindFunctionLeave(); |
349 | |
350 | HRESULT ExceptionUnwindFinallyEnter( |
351 | FunctionID functionId); |
352 | |
353 | HRESULT ExceptionUnwindFinallyLeave(); |
354 | |
355 | HRESULT ExceptionCatcherEnter( |
356 | FunctionID functionId, |
357 | ObjectID objectId); |
358 | |
359 | HRESULT ExceptionCatcherLeave(); |
360 | |
361 | // |
362 | // CCW Events |
363 | // |
364 | |
365 | HRESULT COMClassicVTableCreated( |
366 | /* [in] */ ClassID wrappedClassId, |
367 | /* [in] */ REFGUID implementedIID, |
368 | /* [in] */ void * pVTable, |
369 | /* [in] */ ULONG cSlots); |
370 | |
371 | HRESULT COMClassicVTableDestroyed( |
372 | /* [in] */ ClassID wrappedClassId, |
373 | /* [in] */ REFGUID implementedIID, |
374 | /* [in] */ void * pVTable); |
375 | |
376 | // |
377 | // Remoting Events |
378 | // |
379 | |
380 | HRESULT RemotingClientInvocationStarted(); |
381 | |
382 | HRESULT RemotingClientSendingMessage(GUID * pCookie, |
383 | BOOL fIsAsync); |
384 | |
385 | HRESULT RemotingClientReceivingReply(GUID * pCookie, |
386 | BOOL fIsAsync); |
387 | |
388 | HRESULT RemotingClientInvocationFinished(); |
389 | |
390 | HRESULT RemotingServerReceivingMessage(GUID * pCookie, |
391 | BOOL fIsAsync); |
392 | |
393 | HRESULT RemotingServerInvocationStarted(); |
394 | |
395 | HRESULT RemotingServerInvocationReturned(); |
396 | |
397 | HRESULT RemotingServerSendingReply(GUID * pCookie, |
398 | BOOL fIsAsync); |
399 | |
400 | |
401 | // |
402 | // GC Events |
403 | // |
404 | |
405 | HRESULT RuntimeSuspendStarted(COR_PRF_SUSPEND_REASON suspendReason); |
406 | |
407 | HRESULT RuntimeSuspendFinished(); |
408 | |
409 | HRESULT RuntimeSuspendAborted(); |
410 | |
411 | HRESULT RuntimeResumeStarted(); |
412 | |
413 | HRESULT RuntimeResumeFinished(); |
414 | |
415 | HRESULT RuntimeThreadSuspended(ThreadID suspendedThreadId); |
416 | |
417 | HRESULT RuntimeThreadResumed(ThreadID resumedThreadId); |
418 | |
419 | HRESULT ObjectAllocated( |
420 | /* [in] */ ObjectID objectId, |
421 | /* [in] */ ClassID classId); |
422 | |
423 | HRESULT FinalizeableObjectQueued(BOOL isCritical, ObjectID objectID); |
424 | |
425 | // |
426 | // GC Moved References and RootReferences2 Notification Stuff |
427 | // |
428 | |
429 | HRESULT MovedReference(BYTE * pbMemBlockStart, |
430 | BYTE * pbMemBlockEnd, |
431 | ptrdiff_t cbRelocDistance, |
432 | void * pHeapId, |
433 | BOOL fCompacting); |
434 | |
435 | HRESULT EndMovedReferences(void * pHeapId); |
436 | |
437 | HRESULT RootReference2(BYTE * objectId, |
438 | EtwGCRootKind dwEtwRootKind, |
439 | EtwGCRootFlags dwEtwRootFlags, |
440 | void * rootID, |
441 | void * pHeapId); |
442 | |
443 | HRESULT EndRootReferences2(void * pHeapId); |
444 | |
445 | HRESULT ConditionalWeakTableElementReference(BYTE * primaryObjectId, |
446 | BYTE * secondaryObjectId, |
447 | void * rootID, |
448 | void * pHeapId); |
449 | |
450 | HRESULT EndConditionalWeakTableElementReferences(void * pHeapId); |
451 | |
452 | // |
453 | // GC Root notification stuff |
454 | // |
455 | |
456 | HRESULT AllocByClass(ObjectID objId, ClassID classId, void* pHeapId); |
457 | |
458 | HRESULT EndAllocByClass(void * pHeapId); |
459 | |
460 | // |
461 | // Heap walk notification stuff |
462 | // |
463 | HRESULT ObjectReference(ObjectID objId, |
464 | ClassID classId, |
465 | ULONG cNumRefs, |
466 | ObjectID * arrObjRef); |
467 | |
468 | // |
469 | // GC Handle creation / destruction notifications |
470 | // |
471 | HRESULT HandleCreated(UINT_PTR handleId, ObjectID initialObjectId); |
472 | |
473 | HRESULT HandleDestroyed(UINT_PTR handleId); |
474 | |
475 | HRESULT GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason); |
476 | |
477 | HRESULT GarbageCollectionFinished(); |
478 | |
479 | // |
480 | // Detach |
481 | // |
482 | HRESULT ProfilerDetachSucceeded(); |
483 | |
484 | BOOL HasTimedOutWaitingForConcurrentGC(); |
485 | |
486 | HRESULT GetAssemblyReferences(LPCWSTR wszAssemblyPath, IAssemblyBindingClosure * pClosure, AssemblyReferenceClosureWalkContextForProfAPI * pContext); |
487 | |
488 | private: |
489 | |
490 | // |
491 | // Generation 0 Allocation by Class notification stuff |
492 | // |
493 | |
494 | // This is for a hashing of ClassID values |
495 | struct CLASSHASHENTRY : HASHENTRY |
496 | { |
497 | ClassID m_clsId; // The class ID (also the key) |
498 | size_t m_count; // How many of this class have been counted |
499 | }; |
500 | |
501 | // This is a simple implementation of CHashTable to provide a very simple |
502 | // implementation of the Cmp pure virtual function |
503 | class CHashTableImpl : public CHashTable |
504 | { |
505 | public: |
506 | CHashTableImpl(ULONG iBuckets); |
507 | virtual ~CHashTableImpl(); |
508 | |
509 | protected: |
510 | virtual BOOL Cmp(SIZE_T k1, const HASHENTRY * pc2); |
511 | }; |
512 | |
513 | // This contains the data for storing allocation information |
514 | // in terms of numbers of objects sorted by class. |
515 | struct AllocByClassData |
516 | { |
517 | CHashTableImpl * pHashTable; // The hash table |
518 | CLASSHASHENTRY * arrHash; // Array that the hashtable uses for linking |
519 | ULONG cHash; // The total number of elements in arrHash |
520 | ULONG iHash; // Next empty entry in the hash array |
521 | ClassID * arrClsId; // Array of ClassIDs for the call to ObjectsAllocatedByClass |
522 | ULONG * arrcObjects; // Array of counts for the call to ObjectsAllocatedByClass |
523 | size_t cLength; // Length of the above two parallel arrays |
524 | }; |
525 | |
526 | static const UINT kcReferencesMax = 512; |
527 | |
528 | struct GCReferencesData |
529 | { |
530 | size_t curIdx; |
531 | size_t compactingCount; |
532 | BYTE * arrpbMemBlockStartOld[kcReferencesMax]; |
533 | BYTE * arrpbMemBlockStartNew[kcReferencesMax]; |
534 | union |
535 | { |
536 | size_t arrMemBlockSize[kcReferencesMax]; |
537 | ULONG arrULONG[kcReferencesMax]; |
538 | BYTE * arrpbRootId[kcReferencesMax]; |
539 | }; |
540 | GCReferencesData * pNext; |
541 | }; |
542 | |
543 | // Since this stuff can only be performed by one thread (right now), we don't need |
544 | // to make this thread safe and can just have one block we reuse every time around |
545 | static AllocByClassData * m_pSavedAllocDataBlock; |
546 | |
547 | // Pointer to the profiler's implementation of the callback interface(s). |
548 | // Profilers MUST support ICorProfilerCallback2. |
549 | // Profilers MAY optionally support ICorProfilerCallback3,4,5,6,7,8,9 |
550 | ICorProfilerCallback2 * m_pCallback2; |
551 | ICorProfilerCallback3 * m_pCallback3; |
552 | ICorProfilerCallback4 * m_pCallback4; |
553 | ICorProfilerCallback5 * m_pCallback5; |
554 | ICorProfilerCallback6 * m_pCallback6; |
555 | ICorProfilerCallback7 * m_pCallback7; |
556 | ICorProfilerCallback8 * m_pCallback8; |
557 | ICorProfilerCallback9 * m_pCallback9; |
558 | |
559 | HMODULE m_hmodProfilerDLL; |
560 | |
561 | BOOL m_fLoadedViaAttach; |
562 | ProfToEEInterfaceImpl * m_pProfToEE; |
563 | |
564 | // Used in EEToProfInterfaceImpl.cpp to call into the profiler (see EEFunctionIDMapper) |
565 | FunctionIDMapper * m_pProfilersFuncIDMapper; |
566 | FunctionIDMapper2 * m_pProfilersFuncIDMapper2; |
567 | void * m_pProfilersFuncIDMapper2ClientData; |
568 | |
569 | // This is used as a cookie template for remoting calls |
570 | GUID m_GUID; |
571 | |
572 | // This is an incrementing counter for constructing unique GUIDS from |
573 | // m_GUID |
574 | LONG m_lGUIDCount; |
575 | |
576 | // This will contain a list of free ref data structs, so they |
577 | // don't have to be re-allocated on every GC |
578 | GCReferencesData * m_pGCRefDataFreeList; |
579 | |
580 | // This is for managing access to the free list above. |
581 | CRITSEC_COOKIE m_csGCRefDataFreeList; |
582 | |
583 | FunctionEnter * m_pEnter; |
584 | FunctionLeave * m_pLeave; |
585 | FunctionTailcall * m_pTailcall; |
586 | |
587 | FunctionEnter2 * m_pEnter2; |
588 | FunctionLeave2 * m_pLeave2; |
589 | FunctionTailcall2 * m_pTailcall2; |
590 | |
591 | BOOL m_fIsClientIDToFunctionIDMappingEnabled; |
592 | |
593 | FunctionEnter3 * m_pEnter3; |
594 | FunctionLeave3 * m_pLeave3; |
595 | FunctionTailcall3 * m_pTailcall3; |
596 | |
597 | FunctionEnter3WithInfo * m_pEnter3WithInfo; |
598 | FunctionLeave3WithInfo * m_pLeave3WithInfo; |
599 | FunctionTailcall3WithInfo * m_pTailcall3WithInfo; |
600 | |
601 | |
602 | // Remembers whether the profiler used SetILFunctionBody() which modifies IL in a |
603 | // way that cannot be reverted. This prevents a detach from succeeding. |
604 | BOOL m_fUnrevertiblyModifiedIL; |
605 | |
606 | // Remember whether the profiler has enabled Rejit, and prevent detach if it has. |
607 | BOOL m_fModifiedRejitState; |
608 | |
609 | GCReferencesData * AllocateMovedReferencesData(); |
610 | |
611 | void FreeMovedReferencesData(GCReferencesData * pData); |
612 | |
613 | HRESULT MovedReferences(GCReferencesData * pData); |
614 | |
615 | HRESULT RootReferences2(GCReferencesData * pData); |
616 | |
617 | HRESULT ConditionalWeakTableElementReferences(GCReferencesData * pData); |
618 | |
619 | HRESULT NotifyAllocByClass(AllocByClassData * pData); |
620 | |
621 | HRESULT CreateProfiler( |
622 | const CLSID * pClsid, |
623 | __in_z LPCWSTR wszClsid, |
624 | __in_z LPCWSTR wszProfileDLL); |
625 | |
626 | HRESULT DetermineAndSetEnterLeaveFunctionHooksForJit(); |
627 | |
628 | HRESULT STDMETHODCALLTYPE SetEnterLeaveFunctionHooksForJit( |
629 | FunctionEnter3 * pFuncEnter, |
630 | FunctionLeave3 * pFuncLeave, |
631 | FunctionTailcall3 * pFuncTailcall); |
632 | |
633 | struct FunctionIDAndClientID |
634 | { |
635 | FunctionID functionID; |
636 | UINT_PTR clientID; |
637 | }; |
638 | |
639 | class FunctionIDHashTableTraits : public NoRemoveSHashTraits<DefaultSHashTraits<FunctionIDAndClientID> > |
640 | { |
641 | public: |
642 | |
643 | static const COUNT_T s_minimum_allocation = 31; |
644 | typedef DefaultSHashTraits<FunctionIDAndClientID *>::count_t count_t; |
645 | typedef UINT_PTR key_t; |
646 | |
647 | static key_t GetKey(FunctionIDAndClientID e) |
648 | { |
649 | LIMITED_METHOD_CONTRACT; |
650 | return e.functionID; |
651 | } |
652 | |
653 | static BOOL Equals(key_t k1, key_t k2) |
654 | { |
655 | LIMITED_METHOD_CONTRACT; |
656 | return k1 == k2; |
657 | } |
658 | |
659 | static count_t Hash(key_t k) |
660 | { |
661 | LIMITED_METHOD_CONTRACT; |
662 | return (count_t)k; |
663 | } |
664 | |
665 | static const FunctionIDAndClientID Null() |
666 | { |
667 | LIMITED_METHOD_CONTRACT; |
668 | FunctionIDAndClientID functionIDAndClientID; |
669 | functionIDAndClientID.functionID = NULL; |
670 | functionIDAndClientID.clientID = NULL; |
671 | return functionIDAndClientID; |
672 | } |
673 | |
674 | static bool IsNull(const FunctionIDAndClientID &functionIDAndClientID) |
675 | { |
676 | LIMITED_METHOD_CONTRACT; |
677 | _ASSERTE((functionIDAndClientID.functionID != NULL) || (functionIDAndClientID.clientID == NULL)); |
678 | return functionIDAndClientID.functionID == NULL; |
679 | } |
680 | }; |
681 | |
682 | typedef SHash<FunctionIDHashTableTraits> FunctionIDHashTable; |
683 | |
684 | // ELT3 no long keeps track of FunctionID of current managed method. Therefore, a hash table of bookkeeping |
685 | // the mapping from FunctionID to clientID is needed to build up ELT2 on top of ELT3. When ELT2 (slow-path |
686 | // or fast-path) is registered by the profiler and the profiler's IDFunctionMapper requests to hook up the |
687 | // function being loading, the clientID returned by FunctionIDMapper will be saved as the value to be looked |
688 | // up by the corresponding FunctionID in the hash table. FunctionIDs can be recycled after an app domain |
689 | // that contains the function bodies is unloaded so this hash table needs to replace the existing FunctionID |
690 | // with new FunctionID if a duplication is found in the hash table. |
691 | FunctionIDHashTable * m_pFunctionIDHashTable; |
692 | |
693 | // Since the hash table can be read and writen concurrently, a reader-writer lock is used to synchronize |
694 | // all accesses to the hash table. |
695 | SimpleRWLock * m_pFunctionIDHashTableRWLock; |
696 | |
697 | // Timeout for wait operation on concurrent GC. Only used for attach scenario |
698 | DWORD m_dwConcurrentGCWaitTimeoutInMs; |
699 | |
700 | // Remember the fact we've timed out when waiting for concurrent GC. Will report the error later |
701 | BOOL m_bHasTimedOutWaitingForConcurrentGC; |
702 | }; |
703 | |
704 | #endif // __EETOPROFINTERFACEIMPL_H__ |
705 | |