Add LCG JIT Compilation Profiler Callbacks
[platform/upstream/coreclr.git] / src / vm / eetoprofinterfaceimpl.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 //
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
25 class SimpleRWLock;
26
27 class ProfToEEInterfaceImpl;
28
29 interface IAssemblyBindingClosure;
30 struct AssemblyReferenceClosureWalkContextForProfAPI;
31
32 const GUID k_guidZero = {0};
33
34 class EEToProfInterfaceImpl
35 {
36 public:
37
38     //
39     // Internal initialization / cleanup
40     //
41    
42     EEToProfInterfaceImpl();
43     ~EEToProfInterfaceImpl();
44
45     HRESULT Init(
46         ProfToEEInterfaceImpl * pProfToEE,
47         const CLSID * pClsid,
48         __inout_z LPCWSTR wszClsid, 
49         __in_z LPCWSTR wszProfileDLL,
50         BOOL fLoadedViaAttach,
51         DWORD dwConcurrentGCWaitTimeoutInMs);
52
53     BOOL IsCallback3Supported();
54     BOOL IsCallback4Supported();
55     BOOL IsCallback5Supported();
56     BOOL IsCallback6Supported();
57     BOOL IsCallback7Supported();
58     BOOL IsCallback8Supported();
59
60     HRESULT SetEventMask(DWORD dwEventMask, DWORD dwEventMaskHigh);
61
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);
66
67     FunctionIDMapper * GetFunctionIDMapper();
68     FunctionIDMapper2 * GetFunctionIDMapper2();
69     BOOL IsLoadedViaAttach();
70     HRESULT EnsureProfilerDetachable();
71     void SetUnrevertiblyModifiedILFlag();
72
73     FunctionEnter *              GetEnterHook();
74     FunctionLeave *              GetLeaveHook();
75     FunctionTailcall *           GetTailcallHook();
76
77     FunctionEnter2 *             GetEnter2Hook();
78     FunctionLeave2 *             GetLeave2Hook();
79     FunctionTailcall2 *          GetTailcall2Hook();
80
81     FunctionEnter3 *             GetEnter3Hook();
82     FunctionLeave3 *             GetLeave3Hook();
83     FunctionTailcall3 *          GetTailcall3Hook();
84     FunctionEnter3WithInfo *     GetEnter3WithInfoHook();
85     FunctionLeave3WithInfo *     GetLeave3WithInfoHook();
86     FunctionTailcall3WithInfo *  GetTailcall3WithInfoHook();
87
88     BOOL IsClientIDToFunctionIDMappingEnabled();
89
90     UINT_PTR LookupClientIDFromCache(FunctionID functionID);
91
92     HRESULT SetEnterLeaveFunctionHooks(
93         FunctionEnter * pFuncEnter,
94         FunctionLeave * pFuncLeave,
95         FunctionTailcall * pFuncTailcall);
96
97     HRESULT SetEnterLeaveFunctionHooks2(
98         FunctionEnter2 * pFuncEnter,
99         FunctionLeave2 * pFuncLeave,
100         FunctionTailcall2 * pFuncTailcall);
101
102     HRESULT SetEnterLeaveFunctionHooks3(
103         FunctionEnter3 * pFuncEnter3,
104         FunctionLeave3 * pFuncLeave3,
105         FunctionTailcall3 * pFuncTailcall3);
106
107     HRESULT SetEnterLeaveFunctionHooks3WithInfo(
108         FunctionEnter3WithInfo * pFuncEnter3WithInfo,
109         FunctionLeave3WithInfo * pFuncLeave3WithInfo,
110         FunctionTailcall3WithInfo * pFuncTailcall3WithInfo);
111
112     BOOL RequiresGenericsContextForEnterLeave();
113
114     UINT_PTR EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction);
115
116     // This fills in the non call-specific portions of the cookie GUID.
117     // This should only be called once at startup if necessary.
118     HRESULT InitGUID();
119
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);
124
125     //
126     // Initialize callback
127     //
128
129     HRESULT Initialize();
130
131     HRESULT InitializeForAttach(void * pvClientData, UINT cbClientData);
132
133     HRESULT ProfilerAttachComplete();
134     
135     //
136     // Thread Events
137     //
138     
139     HRESULT ThreadCreated(
140         ThreadID    threadID);
141     
142     HRESULT ThreadDestroyed(
143         ThreadID    threadID);
144
145     HRESULT ThreadAssignedToOSThread(ThreadID managedThreadId,
146                                            DWORD osThreadId);
147
148     HRESULT ThreadNameChanged(ThreadID managedThreadId,
149                               ULONG cchName,
150                               __in_ecount_opt(cchName) WCHAR name[]);
151
152     //
153     // Startup/Shutdown Events
154     //
155     
156     HRESULT Shutdown();
157
158     //
159     // JIT/Function Events
160     //
161     
162     HRESULT FunctionUnloadStarted(
163         FunctionID  functionId);
164
165     HRESULT JITCompilationFinished(
166         FunctionID  functionId, 
167         HRESULT     hrStatus,
168         BOOL        fIsSafeToBlock);
169
170     HRESULT JITCompilationStarted(
171         FunctionID  functionId,
172         BOOL        fIsSafeToBlock);
173
174     HRESULT DynamicMethodJITCompilationStarted(
175         FunctionID  functionId,
176         LPCBYTE     ilHeader);
177
178     HRESULT DynamicMethodJITCompilationFinished(
179         FunctionID functionId);
180     
181     HRESULT JITCachedFunctionSearchStarted(
182         /* [in] */  FunctionID functionId,
183         /* [out] */ BOOL * pbUseCachedFunction);
184
185     HRESULT JITCachedFunctionSearchFinished(
186         /* [in] */  FunctionID functionId,
187         /* [in] */  COR_PRF_JIT_CACHE result);
188
189     HRESULT JITFunctionPitched(FunctionID functionId);
190
191     HRESULT JITInlining(
192         /* [in] */  FunctionID    callerId,
193         /* [in] */  FunctionID    calleeId,
194         /* [out] */ BOOL *        pfShouldInline);
195
196     HRESULT ReJITCompilationStarted(
197         /* [in] */  FunctionID    functionId,
198         /* [in] */  ReJITID       reJitId,
199         /* [in] */  BOOL          fIsSafeToBlock);
200
201     HRESULT GetReJITParameters(
202         /* [in] */  ModuleID      moduleId,
203         /* [in] */  mdMethodDef   methodId,
204         /* [in] */  ICorProfilerFunctionControl *
205                                   pFunctionControl);
206
207     HRESULT ReJITCompilationFinished(
208         /* [in] */  FunctionID    functionId,
209         /* [in] */  ReJITID       reJitId,
210         /* [in] */  HRESULT       hrStatus,
211         /* [in] */  BOOL          fIsSafeToBlock);
212
213     HRESULT ReJITError(
214         /* [in] */  ModuleID      moduleId,
215         /* [in] */  mdMethodDef   methodId,
216         /* [in] */  FunctionID    functionId,
217         /* [in] */  HRESULT       hrStatus);
218
219     //
220     // Module Events
221     //
222     
223     HRESULT ModuleLoadStarted(
224         ModuleID    moduleId);
225
226     HRESULT ModuleLoadFinished(
227         ModuleID    moduleId, 
228         HRESULT     hrStatus);
229     
230     HRESULT ModuleUnloadStarted(
231         ModuleID    moduleId);
232
233     HRESULT ModuleUnloadFinished(
234         ModuleID    moduleId, 
235         HRESULT     hrStatus);
236     
237     HRESULT ModuleAttachedToAssembly( 
238         ModuleID    moduleId,
239         AssemblyID  AssemblyId);
240
241     HRESULT ModuleInMemorySymbolsUpdated(
242         ModuleID    moduleId);
243
244     //
245     // Class Events
246     //
247     
248     HRESULT ClassLoadStarted(
249         ClassID      classId);
250
251     HRESULT ClassLoadFinished(
252         ClassID      classId,
253         HRESULT     hrStatus);
254
255     HRESULT ClassUnloadStarted( 
256         ClassID classId);
257
258     HRESULT ClassUnloadFinished( 
259         ClassID classId,
260         HRESULT hrStatus);
261
262     //
263     // AppDomain Events
264     //
265     
266     HRESULT AppDomainCreationStarted( 
267         AppDomainID appDomainId);
268     
269     HRESULT AppDomainCreationFinished( 
270         AppDomainID appDomainId,
271         HRESULT     hrStatus);
272     
273     HRESULT AppDomainShutdownStarted( 
274         AppDomainID appDomainId);
275     
276     HRESULT AppDomainShutdownFinished( 
277         AppDomainID appDomainId,
278         HRESULT     hrStatus);
279
280     //
281     // Assembly Events
282     //
283
284     HRESULT AssemblyLoadStarted( 
285         AssemblyID  assemblyId);
286     
287     HRESULT AssemblyLoadFinished( 
288         AssemblyID  assemblyId,
289         HRESULT     hrStatus);
290     
291     HRESULT AssemblyUnloadStarted( 
292         AssemblyID  assemblyId);
293     
294     HRESULT AssemblyUnloadFinished( 
295         AssemblyID  assemblyId,
296         HRESULT     hrStatus);
297
298     //
299     // Transition Events
300     //
301
302     HRESULT UnmanagedToManagedTransition(
303         FunctionID functionId,
304         COR_PRF_TRANSITION_REASON reason);
305
306     HRESULT ManagedToUnmanagedTransition(
307         FunctionID functionId,
308         COR_PRF_TRANSITION_REASON reason);
309
310     //
311     // Exception Events
312     //
313
314     HRESULT ExceptionThrown(
315         ObjectID thrownObjectId);
316
317     HRESULT ExceptionSearchFunctionEnter(
318         FunctionID functionId);
319
320     HRESULT ExceptionSearchFunctionLeave();
321
322     HRESULT ExceptionSearchFilterEnter(
323         FunctionID funcId);
324
325     HRESULT ExceptionSearchFilterLeave();
326
327     HRESULT ExceptionSearchCatcherFound(
328         FunctionID functionId);
329
330     HRESULT ExceptionOSHandlerEnter(
331         FunctionID funcId);
332
333     HRESULT ExceptionOSHandlerLeave(
334         FunctionID funcId);
335
336     HRESULT ExceptionUnwindFunctionEnter(
337         FunctionID functionId);
338
339     HRESULT ExceptionUnwindFunctionLeave();
340     
341     HRESULT ExceptionUnwindFinallyEnter(
342         FunctionID functionId);
343
344     HRESULT ExceptionUnwindFinallyLeave();
345     
346     HRESULT ExceptionCatcherEnter(
347         FunctionID functionId,
348         ObjectID objectId);
349
350     HRESULT ExceptionCatcherLeave();
351
352     //
353     // CCW Events
354     //
355
356     HRESULT COMClassicVTableCreated( 
357         /* [in] */ ClassID wrappedClassId,
358         /* [in] */ REFGUID implementedIID,
359         /* [in] */ void * pVTable,
360         /* [in] */ ULONG cSlots);
361     
362     HRESULT COMClassicVTableDestroyed( 
363         /* [in] */ ClassID wrappedClassId,
364         /* [in] */ REFGUID implementedIID,
365         /* [in] */ void * pVTable);
366
367     //
368     // Remoting Events
369     //
370
371     HRESULT RemotingClientInvocationStarted();
372     
373     HRESULT RemotingClientSendingMessage(GUID * pCookie,
374                                          BOOL fIsAsync);
375
376     HRESULT RemotingClientReceivingReply(GUID * pCookie,
377                                          BOOL fIsAsync);
378     
379     HRESULT RemotingClientInvocationFinished();
380
381     HRESULT RemotingServerReceivingMessage(GUID * pCookie,
382                                            BOOL fIsAsync);
383     
384     HRESULT RemotingServerInvocationStarted();
385
386     HRESULT RemotingServerInvocationReturned();
387     
388     HRESULT RemotingServerSendingReply(GUID * pCookie,
389                                        BOOL fIsAsync);
390
391
392     //
393     // GC Events
394     //
395
396     HRESULT RuntimeSuspendStarted(COR_PRF_SUSPEND_REASON suspendReason);
397     
398     HRESULT RuntimeSuspendFinished();
399     
400     HRESULT RuntimeSuspendAborted();
401     
402     HRESULT RuntimeResumeStarted();
403     
404     HRESULT RuntimeResumeFinished();
405
406     HRESULT RuntimeThreadSuspended(ThreadID suspendedThreadId);
407
408     HRESULT RuntimeThreadResumed(ThreadID resumedThreadId);
409
410     HRESULT ObjectAllocated( 
411         /* [in] */ ObjectID objectId,
412         /* [in] */ ClassID classId);
413
414     HRESULT FinalizeableObjectQueued(BOOL isCritical, ObjectID objectID);
415
416     //
417     // GC Moved References and RootReferences2 Notification Stuff
418     //
419
420     HRESULT MovedReference(BYTE * pbMemBlockStart,
421                            BYTE * pbMemBlockEnd,
422                            ptrdiff_t cbRelocDistance,
423                            void * pHeapId,
424                            BOOL fCompacting);
425
426     HRESULT EndMovedReferences(void * pHeapId);
427
428     HRESULT RootReference2(BYTE * objectId,
429                            EtwGCRootKind dwEtwRootKind,
430                            EtwGCRootFlags dwEtwRootFlags,
431                            void * rootID, 
432                            void * pHeapId);
433
434     HRESULT EndRootReferences2(void * pHeapId);
435
436     HRESULT ConditionalWeakTableElementReference(BYTE * primaryObjectId,
437                            BYTE * secondaryObjectId, 
438                            void * rootID, 
439                            void * pHeapId);
440
441     HRESULT EndConditionalWeakTableElementReferences(void * pHeapId);
442
443     //
444     // GC Root notification stuff
445     //
446
447     HRESULT AllocByClass(ObjectID objId, ClassID classId, void* pHeapId);
448
449     HRESULT EndAllocByClass(void * pHeapId);
450
451     //
452     // Heap walk notification stuff
453     //
454     HRESULT ObjectReference(ObjectID objId,
455                             ClassID classId,
456                             ULONG cNumRefs,
457                             ObjectID * arrObjRef);
458
459     //
460     // GC Handle creation / destruction notifications
461     //
462     HRESULT HandleCreated(UINT_PTR handleId, ObjectID initialObjectId);
463
464     HRESULT HandleDestroyed(UINT_PTR handleId);
465
466     HRESULT GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason);
467
468     HRESULT GarbageCollectionFinished();
469
470     //
471     // Detach
472     // 
473     HRESULT ProfilerDetachSucceeded();
474
475     BOOL HasTimedOutWaitingForConcurrentGC();
476
477     HRESULT GetAssemblyReferences(LPCWSTR wszAssemblyPath, IAssemblyBindingClosure * pClosure, AssemblyReferenceClosureWalkContextForProfAPI * pContext);
478
479 private:
480
481     //
482     // Generation 0 Allocation by Class notification stuff
483     //
484
485     // This is for a hashing of ClassID values
486     struct CLASSHASHENTRY : HASHENTRY
487     {
488         ClassID         m_clsId;        // The class ID (also the key)
489         size_t          m_count;        // How many of this class have been counted
490     };
491     
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
495     {
496     public:
497         CHashTableImpl(ULONG iBuckets);
498         virtual ~CHashTableImpl();
499         
500     protected:
501         virtual BOOL Cmp(SIZE_T k1, const HASHENTRY * pc2);
502     };
503
504     // This contains the data for storing allocation information
505     // in terms of numbers of objects sorted by class.
506     struct AllocByClassData
507     {
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
515     };
516
517     static const UINT kcReferencesMax = 512;
518
519     struct GCReferencesData
520     {
521         size_t curIdx;
522         size_t compactingCount;
523         BYTE * arrpbMemBlockStartOld[kcReferencesMax];
524         BYTE * arrpbMemBlockStartNew[kcReferencesMax];
525         union
526         {
527             size_t arrMemBlockSize[kcReferencesMax];
528             ULONG arrULONG[kcReferencesMax];
529             BYTE * arrpbRootId[kcReferencesMax];
530         };
531         GCReferencesData * pNext;
532     };
533
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;
537
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;
549
550     BOOL                    m_fLoadedViaAttach;
551     ProfToEEInterfaceImpl * m_pProfToEE;
552
553     // Used in EEToProfInterfaceImpl.cpp to call into the profiler (see EEFunctionIDMapper)
554     FunctionIDMapper * m_pProfilersFuncIDMapper;
555     FunctionIDMapper2 * m_pProfilersFuncIDMapper2;
556     void * m_pProfilersFuncIDMapper2ClientData;
557
558     // This is used as a cookie template for remoting calls
559     GUID m_GUID;
560
561     // This is an incrementing counter for constructing unique GUIDS from
562     // m_GUID
563     LONG m_lGUIDCount;
564
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;
568
569     // This is for managing access to the free list above.
570     CRITSEC_COOKIE m_csGCRefDataFreeList;
571
572     FunctionEnter *         m_pEnter;
573     FunctionLeave *         m_pLeave;
574     FunctionTailcall *      m_pTailcall;
575
576     FunctionEnter2 *        m_pEnter2;
577     FunctionLeave2 *        m_pLeave2;
578     FunctionTailcall2 *     m_pTailcall2;
579
580     BOOL m_fIsClientIDToFunctionIDMappingEnabled;
581
582     FunctionEnter3 *        m_pEnter3;
583     FunctionLeave3 *        m_pLeave3;
584     FunctionTailcall3 *     m_pTailcall3;
585
586     FunctionEnter3WithInfo *    m_pEnter3WithInfo;
587     FunctionLeave3WithInfo *    m_pLeave3WithInfo;
588     FunctionTailcall3WithInfo * m_pTailcall3WithInfo;
589
590
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;
594     
595     GCReferencesData * AllocateMovedReferencesData();
596
597     void FreeMovedReferencesData(GCReferencesData * pData);
598
599     HRESULT MovedReferences(GCReferencesData * pData);
600
601     HRESULT RootReferences2(GCReferencesData * pData);
602
603     HRESULT ConditionalWeakTableElementReferences(GCReferencesData * pData);
604
605     HRESULT NotifyAllocByClass(AllocByClassData * pData);
606
607     HRESULT CreateProfiler(
608         const CLSID * pClsid,
609         __in_z LPCWSTR wszClsid, 
610         __in_z LPCWSTR wszProfileDLL);
611
612     HRESULT DetermineAndSetEnterLeaveFunctionHooksForJit();
613
614     HRESULT STDMETHODCALLTYPE SetEnterLeaveFunctionHooksForJit(
615         FunctionEnter3 * pFuncEnter,
616         FunctionLeave3 * pFuncLeave,
617         FunctionTailcall3 * pFuncTailcall);
618
619     struct FunctionIDAndClientID
620     {
621         FunctionID functionID;
622         UINT_PTR clientID;
623     };
624
625     class FunctionIDHashTableTraits : public NoRemoveSHashTraits<DefaultSHashTraits<FunctionIDAndClientID> >
626     {
627     public:
628
629         static const COUNT_T s_minimum_allocation = 31;
630         typedef DefaultSHashTraits<FunctionIDAndClientID *>::count_t count_t;
631         typedef UINT_PTR key_t;
632
633         static key_t GetKey(FunctionIDAndClientID e) 
634         { 
635             LIMITED_METHOD_CONTRACT;
636             return e.functionID; 
637         }
638
639         static BOOL Equals(key_t k1, key_t k2) 
640         { 
641             LIMITED_METHOD_CONTRACT;
642             return k1 == k2; 
643         }
644
645         static count_t Hash(key_t k)
646         {
647             LIMITED_METHOD_CONTRACT;
648             return (count_t)k;
649         }
650
651         static const FunctionIDAndClientID Null()
652         {
653             LIMITED_METHOD_CONTRACT;
654             FunctionIDAndClientID functionIDAndClientID;
655             functionIDAndClientID.functionID = NULL;
656             functionIDAndClientID.clientID   = NULL;
657             return functionIDAndClientID;
658         }
659
660         static bool IsNull(const FunctionIDAndClientID &functionIDAndClientID) 
661         { 
662             LIMITED_METHOD_CONTRACT; 
663             _ASSERTE((functionIDAndClientID.functionID != NULL) || (functionIDAndClientID.clientID == NULL));
664             return functionIDAndClientID.functionID == NULL;
665         }
666     };
667
668     typedef SHash<FunctionIDHashTableTraits> FunctionIDHashTable;
669
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;
678
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;
682
683     // Timeout for wait operation on concurrent GC. Only used for attach scenario
684     DWORD m_dwConcurrentGCWaitTimeoutInMs;
685
686     // Remember the fact we've timed out when waiting for concurrent GC. Will report the error later
687     BOOL m_bHasTimedOutWaitingForConcurrentGC;
688 };
689
690 #endif // __EETOPROFINTERFACEIMPL_H__