Remove superfluous 'const' qualifier from trivial return types (#20652)
[platform/upstream/coreclr.git] / src / vm / ibclogger.h
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 // IBClogger.H
5 //
6
7 // 
8 // Infrastructure for recording touches of EE data structures
9 //
10 //
11
12
13 #ifndef IBCLOGGER_H
14 #define IBCLOGGER_H
15
16 #include <holder.h>
17 #include <sarray.h>
18 #include <crst.h>
19 #include <synch.h>
20 #include <shash.h>
21
22 // The IBCLogger class records touches of EE data structures.  It is important to
23 // minimize the overhead of IBC recording on non-recording scenarios.  Our goal is
24 // for all public methods to be inlined, and that the cost of doing the instrumentation
25 // check does not exceed one comparison and one branch.
26 //
27
28 class MethodDesc;
29 class MethodTable;
30 class EEClass;
31 class TypeHandle;
32 struct DispatchSlot;
33 class Module;
34 struct EEClassHashEntry;
35 class IBCLogger;
36
37 extern IBCLogger g_IBCLogger;
38
39 typedef PTR_VOID HashDatum;
40
41 typedef Pair< Module*, mdToken > RidMapLogData;
42
43 #if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
44 #define IBCLOGGER_ENABLED
45 #endif
46
47 #ifdef IBCLOGGER_ENABLED
48 //
49 //  Base class for IBC probe callback
50 // 
51 typedef void (* const pfnIBCAccessCallback)(IBCLogger* pLogger, const void * pValue, const void * pValue2);
52
53 class IbcCallback
54 {
55 public:
56     IbcCallback(pfnIBCAccessCallback pCallback, const void * pValue1, const void * pValue2)
57         : m_pCallback(pCallback), 
58         m_pValue1(pValue1),
59         m_pValue2(pValue2),
60         m_tryCount(0)
61 #ifdef _DEBUG
62         , m_id(0)
63 #endif
64     { LIMITED_METHOD_CONTRACT; }
65
66     void Invoke() const
67     {
68         WRAPPER_NO_CONTRACT;
69
70         m_pCallback(&g_IBCLogger, m_pValue1, m_pValue2);
71     }   
72
73     SIZE_T GetPfn() const
74     {
75         LIMITED_METHOD_CONTRACT;
76
77         return (SIZE_T) m_pCallback;
78     }
79        
80     pfnIBCAccessCallback  GetCallback() const
81     {
82         LIMITED_METHOD_CONTRACT;
83
84         return m_pCallback;
85     }
86
87     const void * GetValue1() const
88     {
89         LIMITED_METHOD_CONTRACT;
90
91         return m_pValue1;
92     }
93
94     const void * GetValue2() const
95     {
96         LIMITED_METHOD_CONTRACT;
97
98         return m_pValue2;
99     }
100
101     void SetValid()
102     {
103         LIMITED_METHOD_CONTRACT;
104 #ifdef _DEBUG
105         m_id = ++s_highestId;
106 #endif
107     }
108
109     void Invalidate()
110     {
111         LIMITED_METHOD_CONTRACT;
112 #ifdef _DEBUG
113         m_id = 0;
114 #endif
115     }
116
117     bool IsValid() const
118     {
119         WRAPPER_NO_CONTRACT;
120
121 #ifdef _DEBUG
122         return (m_id > 0) && (m_id <= s_highestId);
123 #else
124         return true;
125 #endif
126     }
127
128     int IncrementTryCount()
129     {
130         return ++m_tryCount;
131     }
132
133     int GetTryCount() const
134     {
135         return m_tryCount;
136     }
137
138 private:
139     pfnIBCAccessCallback    m_pCallback;
140     const void *            m_pValue1;
141     const void *            m_pValue2;
142
143     int                     m_tryCount;
144
145 #ifdef _DEBUG
146     unsigned                m_id;
147     static unsigned         s_highestId;
148 #endif
149 };
150
151 class DelayCallbackTableTraits : public DefaultSHashTraits< IbcCallback * >
152 {
153 public:
154     typedef IbcCallback * key_t;
155
156     static key_t GetKey(element_t e)
157     {
158         LIMITED_METHOD_CONTRACT;
159         return e;
160     }
161
162     static BOOL Equals(key_t k1, key_t k2)
163     {
164         LIMITED_METHOD_CONTRACT;
165
166         return (k1->GetCallback() == k2->GetCallback()) &&
167                (k1->GetValue1() == k2->GetValue1()) && 
168                (k1->GetValue2() == k2->GetValue2());
169     }   
170
171     static count_t Hash(key_t k)
172     { 
173         LIMITED_METHOD_CONTRACT;
174
175         SIZE_T hashLarge = (SIZE_T)k->GetCallback() ^
176                (SIZE_T)k->GetValue1() ^
177                (SIZE_T)k->GetValue2();
178
179 #if POINTER_BITS == 32
180         // sizeof(SIZE_T) == sizeof(COUNT_T)
181         return hashLarge;
182 #else
183         // xor in the upper half as well.
184         count_t hash = *(count_t *)(&hashLarge);
185         for (unsigned int i = 1; i < POINTER_BITS / 32; i++)
186         {
187             hash ^= ((count_t *)&hashLarge)[i];
188         }
189
190         return hash;
191 #endif // POINTER_BITS
192     }
193
194     static element_t Null()
195 {
196         WRAPPER_NO_CONTRACT;
197         return NULL;
198     }
199     
200     static bool IsNull(element_t e) 
201     {
202         LIMITED_METHOD_CONTRACT;
203         return e == NULL;
204     }
205
206     static element_t Deleted()
207     {
208         WRAPPER_NO_CONTRACT;
209         return (element_t)-1;
210     }   
211
212     static bool IsDeleted(const element_t e)
213     {
214         LIMITED_METHOD_CONTRACT;
215         return e == (element_t)-1;
216     }
217 };
218
219 typedef  SHash< DelayCallbackTableTraits >  DelayCallbackTable;
220
221 class ThreadLocalIBCInfo
222 {
223 public:
224     ThreadLocalIBCInfo();
225     ~ThreadLocalIBCInfo();
226
227     // BOOL IsLoggingDisable()
228     // This indicates that logging is currently disabled for this thread
229     // This is used to prevent the logging functionality from 
230     // triggerring more logging (and thus causing a deadlock)
231     // It is also used to prevent IBC logging whenever a IBCLoggingDisabler
232     // object is used. For example we use this to disable IBC profiling
233     // whenever a thread starts a JIT compile event. That is because we 
234     // don't want to "pollute" the IBC data gathering for the things
235     // that the JIT compiler touches.
236     // Finally since our IBC logging will need to allocate unmanaged memory
237     // we also disable IBC logging when we are inside a "can't alloc region"
238     // Typically this occurs when a thread is performing a GC. 
239     BOOL IsLoggingDisabled()
240     {
241         LIMITED_METHOD_CONTRACT;
242         return m_fLoggingDisabled || IsInCantAllocRegion();
243     }
244
245     // We want to disable IBC logging, any further log calls are to be ignored until 
246     // we call EnableLogging()
247     //
248     // This method returns true if it changed the value of m_fLoggingDisabled from false to true
249     // it returns false if the value of m_fLoggingDisabled was already set to true
250     // after this method executes the value of m_fLoggingDisabled will be true
251     bool DisableLogging()
252     {
253         LIMITED_METHOD_CONTRACT;
254
255         bool result = (m_fLoggingDisabled == false);
256         m_fLoggingDisabled = true;
257
258         return result;
259     }
260
261     // We want to re-enable IBC logging
262     void EnableLogging()
263     {
264         LIMITED_METHOD_CONTRACT;
265
266         _ASSERTE(m_fLoggingDisabled == true);
267
268         m_fLoggingDisabled = false;
269     }
270
271     bool ProcessingDelayedList()
272     {
273         LIMITED_METHOD_CONTRACT;
274         return m_fProcessingDelayedList;
275     }
276
277     void SetCallbackFailed()
278     {
279         LIMITED_METHOD_CONTRACT;
280         m_fCallbackFailed = true;
281     }
282
283     int GetMinCountToProcess()
284     {
285         LIMITED_METHOD_CONTRACT;
286         return m_iMinCountToProcess;
287     }
288
289     void IncMinCountToProcess(int increment)
290     {
291         LIMITED_METHOD_CONTRACT;
292         m_iMinCountToProcess += increment;
293     }
294
295     DelayCallbackTable * GetPtrDelayList();
296
297     void DeleteDelayedCallbacks();
298
299     void FlushDelayedCallbacks();
300
301     int  ProcessDelayedCallbacks();
302
303     void CallbackHelper(const void * p, pfnIBCAccessCallback callback);
304
305 private:
306     bool        m_fProcessingDelayedList;
307     bool        m_fCallbackFailed;
308     bool        m_fLoggingDisabled;
309
310     int         m_iMinCountToProcess;
311
312     DelayCallbackTable * m_pDelayList;
313 };
314
315 class IBCLoggingDisabler
316 {
317 public:
318     IBCLoggingDisabler();
319     IBCLoggingDisabler(bool ignore);      // When ignore is true we treat this as a nop
320     IBCLoggingDisabler(ThreadLocalIBCInfo* pInfo);
321     ~IBCLoggingDisabler();
322
323 private:
324     ThreadLocalIBCInfo* m_pInfo;
325     bool                m_fDisabled;  // true if this holder actually disable the logging
326                                       // false when this is a nested occurance and logging was already disabled
327 };
328
329 //
330 // IBCLoggerAwareAllocMemTracker should be used for allocation of IBC tracked structures during type loading.
331 //
332 // If type loading fails, the delayed IBC callbacks may contain pointers to the failed type or method. 
333 // IBCLoggerAwareAllocMemTracker will ensure that the delayed IBC callbacks are flushed before the memory of
334 // the failed type or method is reclaimed. Otherwise, there would be stale pointers in the delayed IBC callbacks
335 // that would cause crashed during IBC logging.
336 //
337 class IBCLoggerAwareAllocMemTracker : public AllocMemTracker
338 {
339 public:
340     IBCLoggerAwareAllocMemTracker()
341     {
342         WRAPPER_NO_CONTRACT;
343     }
344
345     ~IBCLoggerAwareAllocMemTracker();
346 };
347
348 #else // IBCLOGGER_ENABLED
349
350 typedef const void * pfnIBCAccessCallback;
351
352 class IBCLoggingDisabler
353 {
354 public:
355     IBCLoggingDisabler()
356     {
357     }
358
359     ~IBCLoggingDisabler()
360     {
361     }
362 };
363
364 class ThreadLocalIBCInfo
365 {
366 public:
367     ThreadLocalIBCInfo()
368     {
369     }
370
371     ~ThreadLocalIBCInfo()
372     {
373     }
374 };
375
376 class IBCLoggerAwareAllocMemTracker : public AllocMemTracker
377 {
378 public:
379     IBCLoggerAwareAllocMemTracker()
380     {
381     }
382
383     ~IBCLoggerAwareAllocMemTracker()
384     {
385     }
386 };
387
388 #endif // IBCLOGGER_ENABLED
389
390
391 // IBCLogger is responsible for collecting profile data.  Logging is turned on by the
392 // COMPlus_ZapBBInstr environment variable, and the actual writing to the file 
393 // occurs in code:Module.WriteMethodProfileDataLogFile
394 class IBCLogger
395 {
396     //
397     // Methods for logging EE data structure accesses.  All methods should be defined
398     // using the LOGACCESS macros, which creates the wrapper method that calls the
399     // helper when instrumentation is enabled.  The public name of these methods should
400     // be of the form Log##name##Access where name describes the type of access to be
401     // logged.  The private helpers are implemented in IBClogger.cpp.
402     //
403
404 #ifdef IBCLOGGER_ENABLED
405
406 #define LOGACCESS_PTR(name, type)                       \
407     LOGACCESS(name, type*, (type*), (const void *));
408
409 #define LOGACCESS_VALUE(name, type)                     \
410     LOGACCESS(name, type, *(type*), (const void *)&);
411
412 #define LOGACCESS(name, type, totype, toptr)            \
413 public:                                                 \
414     __forceinline void Log##name##Access(type p)        \
415     {                                                   \
416         WRAPPER_NO_CONTRACT;                               \
417         /* We expect this to get inlined, so that it */ \
418         /* has low overhead when not instrumenting. */  \
419         /* So keep the function really small */         \
420         if ( InstrEnabled() )                           \
421             Log##name##AccessStatic(toptr p);           \
422     }                                                   \
423                                                         \
424 private:                                                \
425     __declspec(noinline) static void Log##name##AccessStatic(const void * p) \
426     {                                                   \
427         WRAPPER_NO_CONTRACT;                               \
428         /* To make the logging callsite as small as */  \
429         /* possible keep the part that passes extra */  \
430         /* argument to LogAccessThreadSafeHelper */     \
431         /* in separate non-inlined static functions */  \
432         LogAccessThreadSafeHelperStatic(p, Log##name##AccessWrapper); \
433     }                                                   \
434                                                         \
435     static void Log##name##AccessWrapper(IBCLogger* pLogger, const void * pValue1, const void * pValue2) \
436     {                                                   \
437         WRAPPER_NO_CONTRACT;                               \
438         return pLogger->Log##name##AccessHelper(totype pValue1); \
439     }                                                   \
440     void Log##name##AccessHelper(type p);               \
441
442 private:
443     static void LogAccessThreadSafeHelperStatic( const void * p, pfnIBCAccessCallback callback);
444     void LogAccessThreadSafeHelper( const void * p, pfnIBCAccessCallback callback);
445
446     void DelayedCallbackPtr(pfnIBCAccessCallback callback, const void * pValue1, const void * pValue2 = NULL);
447
448 #else // FEATURE_PREJIT && !DACCESS_COMPILE
449
450 #define LOGACCESS_PTR(name,type)                        \
451 public:                                                 \
452     void Log##name##Access(type* p) { SUPPORTS_DAC; }   \
453
454 #define LOGACCESS_VALUE(name, type)                     \
455 public:                                                 \
456     void Log##name##Access(type p) { SUPPORTS_DAC; }    \
457
458 #endif // FEATURE_PREJIT && !DACCESS_COMPILE
459
460     // Log access to method desc (which adds the method desc to the required list)
461     // Implemented by : code:IBCLogger.LogMethodDescAccessHelper
462     LOGACCESS_PTR(MethodDesc, const MethodDesc)
463
464     // Log access to method code or method header
465     // Implemented by : code:IBCLogger.LogMethodCodeAccessHelper
466     LOGACCESS_PTR(MethodCode, MethodDesc)
467
468     // Log access to the NDirect data stored for a MethodDesc
469     // also implies that the IL_STUB for the NDirect method is executed
470     // Implemented by : code:IBCLogger.LogNDirectCodeAccessHelper
471     LOGACCESS_PTR(NDirectCode,MethodDesc)
472
473     // Log access to method desc (which addes the method desc to the required list)
474     // Implemented by : code:IBCLogger.LogMethodDescWriteAccessHelper
475     LOGACCESS_PTR(MethodDescWrite,MethodDesc)
476
477     // Log access to method desc (which adds the method desc to the required list)
478     // Implemented by : code:IBCLogger.LogMethodPrecodeAccessHelper
479     LOGACCESS_PTR(MethodPrecode, MethodDesc)
480
481     // Log access to method desc (which addes the method desc to the required list)
482     // Implemented by : code:IBCLogger.LogMethodPrecodeWriteAccessHelper
483     LOGACCESS_PTR(MethodPrecodeWrite,MethodDesc)
484
485     // Log access to gc info
486     // Implemented by : code:IBCLogger.LogMethodGCInfoAccessHelper
487     LOGACCESS_PTR(MethodGCInfo, MethodDesc)
488
489     // Log access to method table
490     // Implemented by : code:IBCLogger.LogMethodTableAccessHelper
491     LOGACCESS_PTR(MethodTable, MethodTable const)
492
493     // Log access to method table
494     // Implemented by : code:IBCLogger.LogTypeMethodTableAccessHelper
495     LOGACCESS_PTR(TypeMethodTable, TypeHandle const)
496
497     // Log write access to method table
498     // Implemented by : code:IBCLogger.LogTypeMethodTableWriteableAccessHelper
499     LOGACCESS_PTR(TypeMethodTableWriteable, TypeHandle const)
500
501     // Log read access to private (written to) method table area
502     // Macro expands to : code:LogMethodTableWriteableDataAccessHelper
503     LOGACCESS_PTR(MethodTableWriteableData, MethodTable const)
504
505     // Log write access to private (written to) method table area
506     // Implemented by : code:IBCLogger.LogMethodTableWriteableDataWriteAccessHelper
507     LOGACCESS_PTR(MethodTableWriteableDataWrite,MethodTable)
508
509     // Log access to method table's NonVirtualSlotsArray
510     // Implemented by : code:IBCLogger.LogMethodTableNonVirtualSlotsAccessHelper
511     LOGACCESS_PTR(MethodTableNonVirtualSlots, MethodTable const)
512
513     // Log access to EEClass
514     // Implemented by : code:IBCLogger.LogEEClassAndMethodTableAccessHelper
515     LOGACCESS_PTR(EEClassAndMethodTable, MethodTable)
516
517     // Log access to EEClass COW table
518     // Implemented by : code:IBCLogger.LogEEClassCOWTableAccessHelper
519     LOGACCESS_PTR(EEClassCOWTable, MethodTable)
520
521     // Log access to the FieldDescs list in the EEClass
522     // Implemented by : code:IBCLogger.LogFieldDescsAccessHelper
523     LOGACCESS_PTR(FieldDescs, FieldDesc)
524
525     // Log access to the MTs dispatch map
526     // Implemented by : code:IBCLogger.LogDispatchMapAccessHelper
527     LOGACCESS_PTR(DispatchMap,MethodTable)
528
529     // Log read access to the MTs dispatch implementation table
530     // Implemented by : code:IBCLogger.LogDispatchTableAccessHelper
531     LOGACCESS_PTR(DispatchTable,MethodTable)
532
533     // Log read access to the MTs dispatch implementation table
534     // Implemented by : code:IBCLogger.LogDispatchTableAccessHelper
535     LOGACCESS_PTR(DispatchTableSlot,DispatchSlot)
536
537     // Log an update to the field marshalers
538     // Implemented by : code:IBCLogger.LogFieldMarshalersReadAccessHelper
539     LOGACCESS_PTR(FieldMarshalersRead,MethodTable)
540
541     // Log a lookup  in the cctor info table
542     // Implemented by : code:IBCLogger.LogCCtorInfoReadAccessHelper
543     LOGACCESS_PTR(CCtorInfoRead,MethodTable)
544
545     // Log a lookup  in the class hash table
546     // Implemented by : code:IBCLogger.LogClassHashTableAccessHelper
547     LOGACCESS_PTR(ClassHashTable,EEClassHashEntry)
548
549     // Log a lookup  of the method list for a CER
550     // Implemented by : code:IBCLogger.LogCerMethodListReadAccessHelper
551     LOGACCESS_PTR(CerMethodListRead,MethodDesc)
552
553     // Log a metadata access
554     // Implemented by : code:IBCLogger.LogMetaDataAccessHelper
555     LOGACCESS_PTR(MetaData,const void)
556
557     // Log a metadata search
558     // Implemented by : code:IBCLogger.LogMetaDataSearchAccessHelper
559     LOGACCESS_PTR(MetaDataSearch,const void)
560
561     // Log a RVA fielddesc access */
562     // Implemented by : code:IBCLogger.LogRVADataAccessHelper
563     LOGACCESS_PTR(RVAData,FieldDesc)
564
565     // Log a lookup  in the type hash table
566     // Implemented by : code:IBCLogger.LogTypeHashTableAccessHelper
567     LOGACCESS_PTR(TypeHashTable,TypeHandle const)
568
569     // Log a lookup  in the Rid map
570     // Implemented by : code:IBCLogger.LogRidMapAccessHelper
571     LOGACCESS_VALUE( RidMap, RidMapLogData );
572
573 public:
574
575 #ifdef IBCLOGGER_ENABLED
576     IBCLogger();
577     ~IBCLogger();
578
579     // Methods for enabling/disabling instrumentation.
580     void EnableAllInstr();
581     void DisableAllInstr();
582 #else // IBCLOGGER_ENABLED
583     void EnableAllInstr()
584     {
585     }
586
587     void DisableAllInstr()
588     {
589     }
590 #endif // IBCLOGGER_ENABLED
591
592 #ifndef DACCESS_COMPILE
593     void DisableRidAccessOrderInstr();
594     void DisableMethodDescAccessInstr();
595
596     inline BOOL InstrEnabled()
597     {
598          SUPPORTS_DAC;
599         return (dwInstrEnabled != 0);
600     }
601
602     static CrstStatic * GetSync();
603
604 private:
605     void LogMethodAccessHelper(const MethodDesc* pMD, ULONG flagNum);
606     static void LogMethodAccessWrapper(IBCLogger* pLogger, const void * pValue1, const void * pValue2);
607
608     void LogTypeAccessHelper(TypeHandle th, ULONG flagNum);
609     static void LogTypeAccessWrapper(IBCLogger* pLogger, const void * pValue1, const void * pValue2);
610
611     BOOL MethodDescAccessInstrEnabled();
612     BOOL RidAccessInstrEnabled();
613
614 private:
615     DWORD dwInstrEnabled;
616     
617     static CrstStatic m_sync;
618 #endif // DACCESS_COMPILE
619 };
620
621 #endif // IBCLOGGER_H