home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 39 / IOPROG_39.ISO / SOFT / sdkjava40.exe / data1.cab / fg_Samples / Samples / Profiler / sampmon / sampmon.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-04  |  68.9 KB  |  2,341 lines

  1. /*++
  2.  
  3. Copyright (c) 1998-1999  Microsoft Corporation, All Rights Reserved
  4.  
  5.  
  6. Defines a simple implementation of these Java VM event monitor interfaces:
  7.     IJavaEventMonitor
  8.     IJavaEventMonitor2
  9.     IHeapInfoCallback
  10.     IObjectAllocationCallback
  11.  
  12.  
  13. To install the event monitor, simply register it, ex.
  14. C:\SDK30\Samples\Profiler\build> regsvr32 sampmon.dll
  15.  
  16. To activate the event monitor, the DWORD registry value
  17. HKEY_CURRENT_USER\Software\Microsoft\Java VM\EnableEventMonitors
  18. must be set to a non-zero value.
  19.  
  20. See the SDK profiler documentation for more information about installation
  21. and activation of profilers.
  22.  
  23.  
  24. The output of the sample monitor may be controlled by setting
  25. various values under the registry key
  26. HKEY_CURRENT_USER\Software\Microsoft\Java VM\Monitors\SampleMonitor
  27.  
  28. The following DWORD values are recognized:
  29.  
  30. RequestedEvents: a bitmask of flags from JAVA_EVENT_CATEGORY (see jevmon.idl
  31.     or the SDK profiler documentation).  For example, if this value is set to
  32.     JVM_MONITOR_CLASS_LOADS, all class load events will be displayed.  Default
  33.     value is ALL_JVM_MONITOR_EVENTS.
  34.  
  35. DumpObjectHeap: if set to a non-zero value, the heap is dumped after each
  36.     garbage collection.  Default value is 1.
  37.     
  38. FollowObjectReferences: if heap dumping is enabled, this enables depth-first
  39.     traversal of the references.  Default value is 0.
  40.  
  41. DisplayObjectAllocations: if set to a non-zero value, outputs a stack trace at
  42.     each object allocation.  Default value is 1.
  43.  
  44. SamplingFrequency: frequency to sample method locations in milliseconds.  If
  45.     set to zero, sampling is disabled.  Default value is 100.
  46.  
  47. SampleData: if sampling is enabled, this is a bitmask of flags from
  48.     JVM_METHOD_SAMPLE_FLAGS indicating the sampling information to obtain and
  49.     display.  Default value is ALL_JVM_SAMPLE_FIELDS.
  50.  
  51. SpecificMethods: specific methods to display entry/exit for.
  52.  
  53.  
  54. --*/
  55.  
  56. #define WIN32_LEAN_AND_MEAN     // for windows.h
  57. #define INC_OLE2                // for windows.h
  58. #define CONST_VTABLE            // for objbase.h
  59.  
  60. #pragma warning(disable:4514)   // "unreferenced inline function" warning
  61.  
  62. #pragma warning(disable:4201)   // "nameless struct/union" warning
  63. #include <windows.h>
  64. #pragma warning(default:4201)   // "nameless struct/union" warning
  65.  
  66. #include <limits.h>
  67. #define DWORD_MAX ULONG_MAX
  68.  
  69. #include "stock.h"
  70. #include <stdio.h>              // for sprintf
  71.  
  72. #pragma warning(disable:4201)   // "nameless struct/union" warning
  73. #include <olectl.h>             // for SELFREG_E_CLASS
  74. #pragma warning(default:4201)   // "nameless struct/union" warning
  75.  
  76. #include <jclshook.h>           // for class loader hooks
  77.  
  78. #include <initguid.h>
  79. #include <jevmon.h>
  80. #include <sampmon.h>            // from nullmon.idl
  81.  
  82. #pragma warning(disable:4710)   // inline function not expanded
  83.  
  84. #pragma hdrstop
  85.  
  86.  
  87. void __cdecl DefineClassStart(const BYTE *pcbyteClass, int ncbClassLen, PBYTE 
  88. *ppbyteReplacementClass, PINT pncbReplacementClassLen)
  89. {
  90.     *ppbyteReplacementClass = new(unsigned char[ncbClassLen]);
  91.  
  92.     if (*ppbyteReplacementClass)
  93.     {
  94.         CopyMemory(*ppbyteReplacementClass, pcbyteClass, ncbClassLen);
  95.         *pncbReplacementClassLen = ncbClassLen;
  96.         // fprintf(stderr, "DefineClassStart(): Replaced class data with duplicate copy.\n");
  97.     }
  98.     else
  99.         *pncbReplacementClassLen = 0;
  100. }
  101.  
  102.  
  103. void __cdecl DefineClassDone(PBYTE pbyteReplacementClass)
  104. {
  105.     delete[](pbyteReplacementClass);
  106.     pbyteReplacementClass = NULL;
  107.     // fprintf(stderr, "DefineClassDone(): Deleted duplicate copy of class data.\n");
  108. }
  109.  
  110.  
  111. enum VMReleases
  112. {
  113.     VM_UNKNOWN,
  114.     VM_IE40,
  115.     VM_SDK30PR1,
  116.     VM_SDK31,
  117.     VM_LATEST,
  118. };
  119.  
  120.  
  121. // All output from the sample profiler funnels through here.
  122.  
  123. VOID Spew (PCSTR fmt, ...)
  124. {
  125.     va_list va;
  126.     va_start(va, fmt);
  127.     vfprintf(stdout, fmt, va);
  128.     va_end(va);
  129. }
  130.  
  131.  
  132. // Maintains a list of active threads from the VM.
  133.  
  134. class ThreadRecordList
  135. {
  136.     friend class ThreadRecordEnumerator;
  137.  
  138.     struct ThreadRecord
  139.     {
  140.         ThreadID vmid;
  141.         DWORD tid;
  142.     };
  143.     CRITICAL_SECTION m_cs;
  144.     ThreadRecord *m_pthreads;
  145.     unsigned m_nthreads;
  146.     unsigned m_maxthreads;
  147.  
  148.     BOOL FindThread (ThreadID vmid, DWORD tid);
  149.  
  150. public:
  151.  
  152.     ThreadRecordList ();
  153.     ~ThreadRecordList ();
  154.  
  155.     VOID AddThread (ThreadID vmid, DWORD tid);
  156.     VOID RemoveThread (ThreadID vmid);
  157.  
  158.     unsigned GetNumThreads () { return m_nthreads; }
  159. };
  160.  
  161. class ThreadRecordEnumerator
  162. {
  163.     ThreadRecordList *m_plist;
  164.     unsigned m_irec;
  165.  
  166. public:
  167.  
  168.     ThreadRecordEnumerator (ThreadRecordList *plist)
  169.     {
  170.         m_plist = plist;
  171.         m_irec = 0;
  172.     
  173.         EnterCriticalSection(&plist->m_cs);
  174.     }
  175.  
  176.     ~ThreadRecordEnumerator ()
  177.     {
  178.         LeaveCriticalSection(&m_plist->m_cs);
  179.     }
  180.  
  181.     BOOL Next (ThreadID *pvmid)
  182.     {
  183.         if (m_irec >= m_plist->m_nthreads)
  184.             return FALSE;
  185.  
  186.         *pvmid = m_plist->m_pthreads[m_irec++].vmid;
  187.         return TRUE;
  188.     }
  189. };
  190.  
  191.  
  192. class SampleEventMonitor : public ISampleJavaEventMonitor,
  193.                            public IHeapInfoCallback,
  194.                            public IObjectAllocationCallback
  195. {
  196. private:
  197.     /* Types
  198.      ********/
  199.  
  200.     typedef enum sample_event_monitior_flags
  201.     {
  202.         // Registered a class loader hook.
  203.  
  204.         SEMF_REGISTERED_CLASS_LOADER_HOOK   = 0x0001,
  205.  
  206.         // Registered a heap callback.
  207.  
  208.         SEMF_REGISTERED_HEAP_CALLBACK       = 0x0002,
  209.  
  210.         // Registered an object allocation callback.
  211.         
  212.         SEMF_REGISTERED_ALLOC_CALLBACK      = 0x0004,
  213.  
  214.         // Traverse references in object heap.
  215.  
  216.         SEMF_TRAVERSE_REFERENCES            = 0x0008,
  217.  
  218.         // Dump the object heap.
  219.  
  220.         SEMF_HEAP_DUMP                      = 0x0010,
  221.  
  222.         // Display object allocations.
  223.  
  224.         SEMF_OBJECT_ALLOCATIONS             = 0x0020,
  225.  
  226.         // flag combinations
  227.  
  228.         ALL_SEM_FLAGS                       = SEMF_REGISTERED_CLASS_LOADER_HOOK |
  229.                                               SEMF_REGISTERED_HEAP_CALLBACK |
  230.                                               SEMF_REGISTERED_ALLOC_CALLBACK |
  231.                                               SEMF_TRAVERSE_REFERENCES |
  232.                                               SEMF_HEAP_DUMP |
  233.                                               SEMF_OBJECT_ALLOCATIONS
  234.     }
  235.     SAMPLEL_EVENT_MONITIOR_FLAGS;
  236.  
  237.     /* Fields
  238.      *********/
  239.  
  240.  
  241.     DWORD   m_dwFlags;      // bit mask of flags from SAMPLE_EVENT_MONITIOR_FLAGS
  242.  
  243.     // Categories of events to monitor
  244.     DWORD   m_dwEvents;     // bit mask of flags from JAVA_EVENT_CATEGORY
  245.  
  246.     VMReleases m_VMRelease;
  247.  
  248.     BOOL    m_fVMInitialized;
  249.     BOOL    m_fVMTerminated;
  250.  
  251.     CRITICAL_SECTION m_cs;
  252.  
  253.  
  254.     // *** IUnknown support
  255.     LPUNKNOWN   m_pUnkOuter;
  256.     UINT    m_cRefs;
  257.  
  258.  
  259.     // *** IJavaEventMonitor support
  260.     PSTR    m_pszClass;
  261.     IJavaEventMonitorIDInfo *m_monitor_info;
  262.     IJavaEventMonitorIDInfo2 *m_monitor_info2;
  263.     IJavaEventMonitorIDInfo3 *m_monitor_info3;
  264.     IJavaEventMonitorIDInfo4 *m_monitor_info4;
  265.  
  266.     // *** IHeapInfoCallback support
  267.     IJavaHeapMonitor *m_HeapMonitor;
  268.     DWORD   m_dwHeapDumpFlags;
  269.     DWORD   m_dwHeapLevel;
  270.     BOOL    m_fMoreRefs;
  271.     DWORD   m_iField;
  272.     BOOL    m_fInHeap;
  273.  
  274.     VOID DumpRef (ObjectID objid, DWORD objflags);
  275.  
  276.     HRESULT InstallHeapMonitorCallbacks (BOOL fEnable);
  277.  
  278.  
  279.     // *** Sampling support
  280.     ThreadRecordList m_ThreadRecords;
  281.     DWORD m_dwSampleFlags;
  282.     DWORD m_dwSamplingFrequency;
  283.     HANDLE m_hSamplerThread;
  284.  
  285.     static DWORD WINAPI SamplerThreadEntry (LPVOID lpThreadParameter);
  286.     DWORD SamplerThread ();
  287.  
  288.     VOID SpewSample (JVM_METHOD_SAMPLE *psample);
  289.  
  290.  
  291.     // Counts of various events
  292.     ULONG m_NumMethodCalls;
  293.     ULONG m_NumMethodReturns;
  294.     ULONG m_NumByteCodesExecuted;
  295.     ULONG m_NumExceptionsThrown;
  296.     ULONG m_NumJITStarts;
  297.     ULONG m_NumJITStops;
  298.     ULONG m_NumMonitorsEntered;
  299.     ULONG m_NumClassesLoaded;
  300.     ULONG m_NumGCs;
  301.  
  302.  
  303.     // Method hooking support
  304.  
  305.     ULONG m_nMethodsToHook;
  306.     PSTR *m_MethodsToHook;
  307.     ULONG m_nClassesToHook;
  308.     PSTR *m_ClassesToHook;
  309.  
  310.     VOID SpewValue (CHAR chsig, PVOID pvalue);
  311.  
  312.     HRESULT SpewStackFrame (PCSTR pszOperation, MethodID method_id, StackID stack_id);
  313.     void PrintStackLeader ();
  314.     
  315.  
  316. public:
  317.     SampleEventMonitor(LPUNKNOWN);
  318.     ~SampleEventMonitor();
  319.  
  320.  
  321.     // *** IUnknown interface
  322.  
  323.     STDMETHODIMP QueryInterface(REFIID, void **);
  324.     STDMETHODIMP_(ULONG) AddRef(void);
  325.     STDMETHODIMP_(ULONG) Release(void);
  326.  
  327.     // *** IJavaEventMonitor interface
  328.  
  329.     STDMETHODIMP Initialize(LPCSTR pclass_file_name, IJavaEventMonitorIDInfo *pmonitor_info, DWORD java_flags, DWORD *prequested_events);
  330.     STDMETHODIMP NotifyEvent(JVM_EVENT_TYPE event, UniqueID event_id);
  331.     STDMETHODIMP MethodEntry(MethodID method_id, StackID stack_id);
  332.     STDMETHODIMP MethodExit(StackID stack_id);
  333.     STDMETHODIMP ExecuteByteCode(MethodID method_id, BYTE_CODE *pbyte_code, DWORD byte_code_offset);
  334.     STDMETHODIMP ExecuteSourceLine(MethodID method_id, DWORD line_number);
  335.  
  336.     // *** IJavaEventMonitor2 interface
  337.  
  338.     STDMETHODIMP NotifyEvent2(JVM_EVENT_TYPE2 event2, UniqueID first_event_id, UniqueID second_event_id);
  339.     STDMETHODIMP MethodExit2(MethodID method_id, StackID stack_id);
  340.     STDMETHODIMP GetPossibleEventCategories(DWORD *ppossible_events);
  341.  
  342.     // *** IHeapInfoCallback interface
  343.  
  344.     STDMETHODIMP BeginContainer(CONTAINER_TYPE type, UniqueID id1, UniqueID id2);
  345.     STDMETHODIMP RootReferences(const ObjectID *prefs, unsigned nrefs, const DWORD *pflags);
  346.     STDMETHODIMP ObjectReferences(ObjectID id, DWORD flags, const ObjectID *prefs, unsigned nrefs, const DWORD *pflags);
  347.  
  348.     // *** IObjectAllocationCallback interface
  349.  
  350.     STDMETHODIMP OnObjectAllocated(ObjectID oid, ClassID type);
  351. };
  352.  
  353. // This class factory class creates SampleEventMonitor objects.
  354. class SampleEventMonitorFactory : public IClassFactory
  355. {
  356. public:
  357.  
  358.     SampleEventMonitorFactory(void);
  359.     ~SampleEventMonitorFactory(void);
  360.  
  361.     // *** IUnknown support
  362.     ULONG           m_cRefs;
  363.  
  364.     // *** IUnknown interface
  365.     STDMETHODIMP QueryInterface(REFIID, void **);
  366.     STDMETHODIMP_(ULONG) AddRef(void);
  367.     STDMETHODIMP_(ULONG) Release(void);
  368.  
  369.     // *** IClassFactory interface
  370.     STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, void **);
  371.     STDMETHODIMP LockServer(BOOL);
  372. };
  373.  
  374.  
  375. // Support for being an in-proc server
  376. // DLL interface and class factory
  377.  
  378. HINSTANCE g_hInst = NULL;
  379.  
  380. BOOL WINAPI
  381. DllMain(HINSTANCE hInst, ULONG reason, LPVOID reserved)
  382. {
  383.     g_hInst = hInst; // remember ourselves for registration code below
  384.  
  385.     return TRUE;
  386. }
  387.  
  388. STDMETHODIMP
  389. DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
  390. {
  391.     HRESULT hr = E_FAIL;
  392.     *ppv = NULL;
  393.     
  394.     if (riid == IID_IUnknown || riid == IID_IClassFactory)
  395.     {
  396.         SampleEventMonitorFactory *class_factory =  new SampleEventMonitorFactory();
  397.         if (class_factory)
  398.         {
  399.             *ppv = (LPVOID)class_factory;
  400.             hr = S_OK;
  401.         }
  402.         else
  403.         {
  404.             hr = E_OUTOFMEMORY;
  405.         }
  406.     }
  407.     
  408.     return hr;
  409. }
  410.  
  411. STDMETHODIMP
  412. DllCanUnloadNow(void)
  413. {
  414.     // TODO: Keep reference count.
  415.     return S_FALSE;
  416. }
  417.  
  418. // Various constants used during self-registration
  419. const char *g_monitor_clsid     = "{E392B230-D8A9-11d1-B041-006008039BF0}"; // our GUID
  420. const char *g_monitor_threading_model   = "Both"; // threading model ("Both" is required by JavaVM since it is free threaded)
  421. const char *g_monitor_description   = "Sample Java VM Event Monitor."; // description of us
  422. const char *g_monitor_progid        = "ISampleJavaEventMonitor"; // program id
  423.  
  424. // We register as a subkey under the Java VM Monitors key
  425. // Create a subkey for our monitor and set several properties
  426. const char *g_monitor_JavaVM_key    = "SOFTWARE\\Microsoft\\Java VM\\Monitors\\SampleMonitor";
  427. const char *g_monitor_option        = "null";
  428. const DWORD g_monitor_flags         = ALL_JVM_MONITOR_EVENTS;
  429.  
  430. STDMETHODIMP
  431. DllRegisterServer(VOID)
  432. {
  433.     HRESULT hr = SELFREG_E_CLASS;
  434.     HKEY    hKey  = NULL;
  435.     HKEY    hKey2 = NULL;
  436.     HKEY    hKey3 = NULL;
  437.     DWORD   result;
  438.     char    module_path_name[MAX_PATH];
  439.  
  440.     // If we fail in the middle, the state of the registry entries
  441.     // is indeterminate (as per OLE specs.)
  442.  
  443.  
  444.     // Create HKEY_CLASSES_ROOT\<progid>...
  445.     result = ::RegCreateKey(HKEY_CLASSES_ROOT, g_monitor_progid, &hKey);
  446.     if (result != ERROR_SUCCESS) {
  447.     goto lExit;
  448.     }
  449.     // Set HKEY_CLASSES_ROOT\<progid> (default) = <desc>
  450.     result = ::RegSetValue(hKey, NULL, REG_SZ, g_monitor_description, lstrlen(g_monitor_description));
  451.     if (result != ERROR_SUCCESS) {
  452.     goto lExit;
  453.     }
  454.     // Create HKEY_CLASSES_ROOT\<progid>\CLSID...
  455.     result = ::RegCreateKey(hKey, TEXT("CLSID"), &hKey2);
  456.     if (result != ERROR_SUCCESS) {
  457.     goto lExit;
  458.     }
  459.     // Set HKEY_CLASSES_ROOT\<progid>\CLSID (default) = <clsid>
  460.     result = ::RegSetValue(hKey2, NULL, REG_SZ, g_monitor_clsid, lstrlen(g_monitor_clsid));
  461.     if (result != ERROR_SUCCESS) {
  462.     goto lExit;
  463.     }
  464.  
  465.     ::RegCloseKey(hKey);
  466.     ::RegCloseKey(hKey2);
  467.     hKey = NULL;
  468.     hKey2 = NULL;
  469.  
  470.  
  471.     // Create HKEY_CLASSES_ROOT\CLSID\...
  472.     result = ::RegCreateKey(HKEY_CLASSES_ROOT, TEXT("CLSID"), &hKey);
  473.     if (result != ERROR_SUCCESS) {
  474.     goto lExit;
  475.     }
  476.     // Create HKEY_CLASSES_ROOT\CLSID\<clsid> ...
  477.     result = ::RegCreateKey(hKey, g_monitor_clsid, &hKey2);
  478.     if (result != ERROR_SUCCESS) {
  479.     goto lExit;
  480.     }
  481.     // Set HKEY_CLASSES_ROOT\CLSID\<clsid> (default) = <desc>
  482.     result = ::RegSetValue(hKey2, NULL, REG_SZ, g_monitor_description, lstrlen(g_monitor_description));
  483.     if (result != ERROR_SUCCESS) {
  484.     goto lExit;
  485.     }
  486.     // Create HKEY_CLASSES_ROOT\CLSID\<clsid>\InprocServer32....
  487.     result = ::RegCreateKey(hKey2, "InprocServer32", &hKey3);
  488.     if (result != ERROR_SUCCESS) {
  489.     goto lExit;
  490.     }
  491.  
  492.     result = GetModuleFileName(g_hInst, module_path_name, sizeof(module_path_name)/sizeof(char));
  493.     if (result == 0) {  //No way to detect truncation from GetModuleFileName.
  494.     goto lExit;
  495.     }
  496.     // Set HKEY_CLASSES_ROOT\CLSID\<clsid>\InprocServer32 (default) = <module_name>
  497.     result = ::RegSetValue(hKey3, NULL, REG_SZ, module_path_name, lstrlen(module_path_name));
  498.     if (result != ERROR_SUCCESS) {
  499.     goto lExit;
  500.     }
  501.     // Set HKEY_CLASSES_ROOT\CLSID\<clsid>\InprocServer32\ThreadingModel = <tm>
  502.     result = ::RegSetValueEx(hKey3, "ThreadingModel", 0, REG_SZ, (BYTE*)g_monitor_threading_model, sizeof(g_monitor_threading_model));
  503.     if (result != ERROR_SUCCESS) {
  504.     goto lExit;
  505.     }
  506.  
  507.     ::RegCloseKey(hKey3);
  508.     hKey3 = NULL;
  509.  
  510.     // Create HKEY_CLASSES_ROOT\CLSID\<clsid>\ProgID...
  511.     result = ::RegCreateKey(hKey2, "ProgID", &hKey3);
  512.     if (result != ERROR_SUCCESS) {
  513.     goto lExit;
  514.     }
  515.     // Set HKEY_CLASSES_ROOT\CLSID\<clsid>\ProgID = <progid>
  516.     result = ::RegSetValue(hKey3, NULL, REG_SZ, g_monitor_progid, lstrlen(g_monitor_progid));
  517.     if (result != ERROR_SUCCESS) {
  518.     goto lExit;
  519.     }
  520.     ::RegCloseKey(hKey3);
  521.     hKey3 = NULL;
  522.  
  523.     // What about HKEY_CLASSES_ROOT\Interface\<clsid> (default) = <progid> ??
  524.     ::RegCloseKey(hKey);
  525.     ::RegCloseKey(hKey2);
  526.     hKey = NULL;
  527.     hKey2 = NULL;
  528.  
  529.     // Now register us as a monitor with the Java VM
  530.     // Create HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Java VM\Monitors\<monitor>
  531.     result = ::RegCreateKey(HKEY_LOCAL_MACHINE, g_monitor_JavaVM_key, &hKey);
  532.     if (result != ERROR_SUCCESS) {
  533.     goto lExit;
  534.     }
  535.     // Set HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Java VM\Monitors\<monitor> = <desc>
  536.     result = ::RegSetValue(hKey, NULL, REG_SZ, g_monitor_description, lstrlen(g_monitor_description));
  537.     if (result != ERROR_SUCCESS) {
  538.     goto lExit;
  539.     }
  540.  
  541.     // Set HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Java VM\Monitors\<monitor>\CLSID = <clsid>
  542.     result = ::RegSetValueEx(hKey, "CLSID", 0, REG_SZ, (BYTE*)g_monitor_clsid, lstrlen(g_monitor_clsid));
  543.     if (result != ERROR_SUCCESS) {
  544.     goto lExit;
  545.     }
  546.  
  547.     // Set HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Java VM\Monitors\<monitor>\Option = <option>
  548.     result = ::RegSetValueEx(hKey, "Option", 0, REG_SZ, (BYTE*)g_monitor_option, lstrlen(g_monitor_option));
  549.     if (result != ERROR_SUCCESS) {
  550.     goto lExit;
  551.     }
  552.  
  553.     ::RegCloseKey(hKey);
  554.     hKey = NULL;
  555.  
  556.     hr = S_OK;
  557.  
  558.   lExit:
  559.     if (hKey) {
  560.     ::RegCloseKey(hKey);
  561.     }
  562.     if (hKey2) {
  563.     ::RegCloseKey(hKey2);
  564.     }
  565.     if (hKey3) {
  566.     ::RegCloseKey(hKey3);
  567.     }
  568.     return hr;
  569.  
  570. }
  571.  
  572. STDMETHODIMP
  573. DllUnregisterServer(VOID)
  574. {
  575.     HRESULT hr = SELFREG_E_CLASS;
  576.     DWORD   result;
  577.  
  578.     result = ::RegDeleteKey(HKEY_LOCAL_MACHINE, g_monitor_JavaVM_key);
  579.     if (result != ERROR_SUCCESS) {
  580.     goto lExit;
  581.     }
  582.     hr = S_OK;
  583.  
  584.   lExit:
  585.     return hr;
  586.  
  587. }
  588.  
  589. // Implementation of the EventMonitor class factory
  590. // Constructors and destructors for the factory
  591. SampleEventMonitorFactory::SampleEventMonitorFactory()
  592. {
  593.     // IUknown
  594.     m_cRefs = 1;
  595.     // IJavaEventMonitor
  596. }
  597.  
  598. SampleEventMonitorFactory::~SampleEventMonitorFactory()
  599. {
  600.     // IUknown
  601.     // IJavaEventMonitor
  602. }
  603.  
  604. // Support for IUknown interface
  605. STDMETHODIMP
  606. SampleEventMonitorFactory::QueryInterface(REFIID riid, void ** ppv)
  607. {
  608.     if (riid == IID_IUnknown || riid == IID_IClassFactory) {
  609.       AddRef();
  610.       *ppv = this;
  611.       return S_OK;
  612.     }
  613.     else {
  614.       *ppv = NULL;
  615.       return E_NOINTERFACE;
  616.     }
  617. }
  618.  
  619. ULONG
  620. SampleEventMonitorFactory::AddRef(void)
  621. {
  622.     return (ULONG)::InterlockedIncrement((LPLONG)&m_cRefs);
  623. }
  624.  
  625. ULONG
  626. SampleEventMonitorFactory::Release(void)
  627. {
  628.     ULONG remaining_refs = (ULONG)::InterlockedDecrement((LPLONG)&m_cRefs);
  629.     if (!remaining_refs) {
  630.       delete this;
  631.     }
  632.     return remaining_refs;
  633. }
  634.  
  635. // CreateInstance and LockServer
  636. STDMETHODIMP
  637. SampleEventMonitorFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void ** ppv)
  638. {
  639.     SampleEventMonitor *monitor = new SampleEventMonitor(pUnkOuter);
  640.     *ppv = NULL;
  641.     // Additional initialization occurs later under Initialize()
  642.     if (monitor) {
  643.     HRESULT query_result = monitor->QueryInterface(riid, ppv);
  644.     // Unlike factory, the caller does AddRef
  645.     if  (query_result != S_OK) {
  646.         // Guess we didn't support that interface
  647.         // Lose this object
  648.         delete monitor;
  649.     }
  650.     return query_result;
  651.     } else {
  652.     return E_FAIL;
  653.     }
  654. }
  655.  
  656. STDMETHODIMP
  657. SampleEventMonitorFactory::LockServer(BOOL fLock)
  658. {
  659.     return CoLockObjectExternal(this, fLock, TRUE);
  660. }
  661.  
  662.  
  663. // ThreadRecordList
  664.  
  665. ThreadRecordList::ThreadRecordList ()
  666. {
  667.     m_nthreads = 0;
  668.     m_maxthreads = 0;
  669.  
  670.     InitializeCriticalSection(&m_cs);
  671. }
  672.  
  673. ThreadRecordList::~ThreadRecordList ()
  674. {
  675.     DeleteCriticalSection(&m_cs);
  676. }
  677.  
  678. BOOL ThreadRecordList::FindThread (ThreadID vmid, DWORD tid)
  679. {
  680.     if (m_pthreads == NULL)
  681.         return FALSE;
  682.  
  683.     unsigned i;
  684.     for (i = 0; i < m_nthreads; i++)
  685.     {
  686.         if (m_pthreads[i].vmid == vmid && m_pthreads[i].tid == tid)
  687.             return TRUE;
  688.     }
  689.  
  690.     return FALSE;
  691. }
  692.  
  693. VOID ThreadRecordList::AddThread (ThreadID vmid, DWORD tid)
  694. {
  695.     EnterCriticalSection(&m_cs);
  696.     {
  697.         if (!FindThread(vmid, tid))
  698.         {
  699.             if (m_nthreads >= m_maxthreads)
  700.             {
  701.                 unsigned newmax = (m_maxthreads+1)*2;
  702.                 ThreadRecord *newthreads = new(ThreadRecord[newmax]);
  703.                 if (newthreads != NULL)
  704.                 {
  705.                     CopyMemory(newthreads, m_pthreads, sizeof(ThreadRecord)*m_maxthreads);
  706.                     delete(m_pthreads);
  707.                     m_maxthreads = newmax;
  708.                     m_pthreads = newthreads;
  709.                 }
  710.             }
  711.  
  712.             if (m_nthreads < m_maxthreads)
  713.             {
  714.                 m_pthreads[m_nthreads].vmid = vmid;
  715.                 m_pthreads[m_nthreads].tid = tid;
  716.                 m_nthreads++;
  717.             }
  718.         }
  719.         else
  720.         {
  721.             Spew("Already received thread creation notification for thread %x.\n", vmid);
  722.         }
  723.     }
  724.     LeaveCriticalSection(&m_cs);
  725. }
  726.  
  727. VOID ThreadRecordList::RemoveThread (ThreadID vmid)
  728. {
  729.     EnterCriticalSection(&m_cs);
  730.     {
  731.         if (m_pthreads != NULL)
  732.         {
  733.             unsigned i;
  734.             for (i = 0; i < m_nthreads; i++)
  735.             {
  736.                 if (m_pthreads[i].vmid == vmid)
  737.                 {
  738.                     m_nthreads--;
  739.                     m_pthreads[i] = m_pthreads[m_nthreads];
  740.                     break;
  741.                 }
  742.             }
  743.         }
  744.     }
  745.     LeaveCriticalSection(&m_cs);
  746. }
  747.  
  748.  
  749. // Implementation of IJavaEventMonitor
  750.  
  751. // Constructors and destructors for our implementation
  752. SampleEventMonitor::SampleEventMonitor(LPUNKNOWN pUnkOuter)
  753. {
  754.     m_pszClass = NULL;
  755.     // IUknown
  756.     m_pUnkOuter = pUnkOuter;
  757.     m_cRefs = 0;
  758.     m_monitor_info = NULL;
  759.     m_monitor_info2 = NULL;
  760.     m_monitor_info3 = NULL;
  761.     m_monitor_info4 = NULL;
  762.     
  763.     InitializeCriticalSection(&m_cs);
  764.     
  765.     m_dwFlags = 0;
  766.     m_fVMInitialized = FALSE;
  767.     m_fVMTerminated = FALSE;
  768.  
  769.     m_dwHeapDumpFlags = 0;
  770.     m_dwHeapLevel = 0;
  771.  
  772.     m_hSamplerThread = INVALID_HANDLE_VALUE;
  773.  
  774.     m_nMethodsToHook = 0;
  775.     m_MethodsToHook = NULL;
  776.     m_nClassesToHook = 0;
  777.     m_ClassesToHook = NULL;
  778. }
  779.  
  780. SampleEventMonitor::~SampleEventMonitor(void)
  781. {
  782.     if (m_pszClass)
  783.     {
  784.         delete(m_pszClass);
  785.         m_pszClass = NULL;
  786.     }
  787.  
  788.     if (m_monitor_info4)
  789.     {
  790.         m_monitor_info4->Release();
  791.         m_monitor_info4 = NULL;
  792.     }
  793.  
  794.     if (m_monitor_info3)
  795.     {
  796.         m_monitor_info3->Release();
  797.         m_monitor_info3 = NULL;
  798.     }
  799.  
  800.     if (m_monitor_info2)
  801.     {
  802.         m_monitor_info2->Release();
  803.         m_monitor_info2 = NULL;
  804.     }
  805.  
  806.     if (m_monitor_info)
  807.     {
  808.         m_monitor_info->Release();
  809.         m_monitor_info = NULL;
  810.     }
  811.  
  812.     if (m_dwFlags & SEMF_REGISTERED_CLASS_LOADER_HOOK)
  813.     {
  814.         DeregisterDefineClassHook();
  815.  
  816.         m_dwFlags &= ~SEMF_REGISTERED_CLASS_LOADER_HOOK;
  817.     }
  818.  
  819.     DeleteCriticalSection(&m_cs);
  820. }
  821.  
  822. void SampleEventMonitor::PrintStackLeader ()
  823. {
  824.     UINT ucStackDepth;
  825.  
  826.     for (ucStackDepth = m_NumMethodCalls - m_NumMethodReturns; ucStackDepth > 0; ucStackDepth--)
  827.         Spew(" ");
  828.  
  829.     return;
  830. }
  831.  
  832. // Support for IUknown interface
  833.  
  834. ULONG SampleEventMonitor::AddRef(void)
  835. {
  836.     return (ULONG)::InterlockedIncrement((LPLONG)&m_cRefs);
  837. }
  838.  
  839. ULONG SampleEventMonitor::Release(void)
  840. {
  841.     ULONG remaining_refs = (ULONG)::InterlockedDecrement((LPLONG)&m_cRefs);
  842.     if (!remaining_refs) {
  843.       delete this;
  844.     }
  845.     return remaining_refs;
  846. }
  847.  
  848. STDMETHODIMP SampleEventMonitor::QueryInterface(REFIID riid, void ** ppv)
  849. {
  850.     if (riid == IID_IJavaEventMonitor ||
  851.         riid == IID_IJavaEventMonitor2 ||
  852.         riid == IID_IUnknown )
  853.     {
  854.         AddRef();
  855.         *ppv = (IJavaEventMonitor2 *)this;
  856.         return S_OK;
  857.     }
  858.     else if (riid == IID_IHeapInfoCallback)
  859.     {
  860.         AddRef();
  861.         *ppv = (IHeapInfoCallback *)this;
  862.         return S_OK;
  863.     }
  864.     else if (riid == IID_IObjectAllocationCallback)
  865.     {
  866.         AddRef();
  867.         *ppv = (IObjectAllocationCallback *)this;
  868.         return S_OK;
  869.     }
  870.     else
  871.     {
  872.         *ppv = NULL;
  873.         return E_NOINTERFACE;
  874.     }
  875. }
  876.  
  877.  
  878. BOOL GetRegDWORD (HKEY hkey, PCSTR valname, DWORD *pvalue, DWORD defvalue)
  879. {
  880.     BOOL result;
  881.     DWORD size = sizeof(*pvalue);
  882.     DWORD type;
  883.  
  884.     result = RegQueryValueEx(
  885.             hkey,
  886.             valname,
  887.             NULL,
  888.             &type,
  889.             (PBYTE)pvalue,
  890.             &size
  891.             ) == ERROR_SUCCESS;
  892.  
  893.     if (!result)
  894.         *pvalue = defvalue;
  895.  
  896.     return result;
  897. }
  898.  
  899. BOOL GetRegFlag (HKEY hkey, PCSTR valname, DWORD *pflags, DWORD mask, BOOL fdefault)
  900. {
  901.     BOOL result;
  902.  
  903.     DWORD val;
  904.     if (!(result = GetRegDWORD(hkey, valname, &val, mask)))
  905.         val = fdefault;
  906.  
  907.     if (val != 0)
  908.         *pflags |= mask;
  909.     else
  910.         *pflags &= ~mask;
  911.  
  912.     return result;
  913. }
  914.  
  915.  
  916. BOOL GrowStringArray (PSTR **ppArray, ULONG *pCount)
  917. {
  918.     PSTR *pNewArray = new(PSTR[*pCount+1]);
  919.     if (pNewArray == NULL)
  920.         return FALSE;
  921.  
  922.     CopyMemory(pNewArray, *ppArray, *pCount * sizeof(PSTR));
  923.     
  924.     *ppArray = pNewArray;
  925.     *pCount = *pCount + 1;
  926.     return TRUE;
  927. }
  928.  
  929.  
  930. // IJavaEventMonitor methods
  931.  
  932. STDMETHODIMP SampleEventMonitor::Initialize(LPCSTR pclass_file_name, IJavaEventMonitorIDInfo *pmonitor_info, DWORD java_flags, DWORD *prequested_events)
  933. {
  934.     HRESULT hr = S_OK;
  935.  
  936.     m_dwEvents = g_monitor_flags;
  937.  
  938.     m_VMRelease = VM_LATEST;
  939.     
  940.     m_monitor_info = pmonitor_info;
  941.     m_monitor_info->AddRef();
  942.  
  943.     if (m_monitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo4, (void **)&m_monitor_info4) != S_OK)
  944.     {
  945.         m_monitor_info4 = NULL;
  946.         m_VMRelease = VM_SDK31;
  947.     }
  948.  
  949.     if (m_monitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo3, (void **)&m_monitor_info3) != S_OK)
  950.     {
  951.         m_monitor_info3 = NULL;
  952.         m_VMRelease = VM_SDK30PR1;
  953.     }
  954.  
  955.     if (m_monitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo2, (void **)&m_monitor_info2) != S_OK)
  956.     {
  957.         m_monitor_info2 = NULL;
  958.         m_VMRelease = VM_IE40;
  959.     }
  960.  
  961.     if (m_monitor_info->QueryInterface(IID_IJavaHeapMonitor, (PVOID*)&m_HeapMonitor) != S_OK)
  962.         m_HeapMonitor = NULL;
  963.  
  964.     HKEY hknm;
  965.     if (RegOpenKeyEx(
  966.             HKEY_CURRENT_USER,
  967.             g_monitor_JavaVM_key,
  968.             0,
  969.             KEY_QUERY_VALUE,
  970.             &hknm
  971.             ) == ERROR_SUCCESS)
  972.     {
  973.         GetRegDWORD(hknm, "RequestedEvents", &m_dwEvents, ALL_JVM_MONITOR_EVENTS);
  974.  
  975.         GetRegFlag(hknm, "FollowObjectReferences", &m_dwFlags, SEMF_TRAVERSE_REFERENCES, FALSE);
  976.  
  977.         GetRegFlag(hknm, "DumpObjectHeap", &m_dwFlags, SEMF_HEAP_DUMP, TRUE);
  978.  
  979.         GetRegFlag(hknm, "DisplayObjectAllocations", &m_dwFlags, SEMF_OBJECT_ALLOCATIONS, TRUE);
  980.  
  981.         GetRegDWORD(hknm, "SampleData", &m_dwSampleFlags, ALL_JVM_SAMPLE_FIELDS);
  982.  
  983.         GetRegDWORD(hknm, "SamplingFrequency", &m_dwSamplingFrequency, 100);
  984.  
  985.         if (m_monitor_info3 != NULL)
  986.         {
  987.             DWORD size = 0;
  988.             DWORD type;
  989.  
  990.             if (RegQueryValueEx(
  991.                     hknm,
  992.                     "SpecificMethods",
  993.                     NULL,
  994.                     &type,
  995.                     NULL,
  996.                     &size
  997.                     ) == ERROR_SUCCESS)
  998.             {
  999.                 PSTR psz = new CHAR[size+1];
  1000.                 if (psz != NULL)
  1001.                 {
  1002.                     if (RegQueryValueEx(
  1003.                             hknm,
  1004.                             "SpecificMethods",
  1005.                             NULL,
  1006.                             &type,
  1007.                             (BYTE*)psz,
  1008.                             &size
  1009.                             ) == ERROR_SUCCESS)
  1010.                     {
  1011.                         CHAR *p = psz;
  1012.  
  1013.                         if (*p != '\0')
  1014.                         {
  1015.                             while (1)
  1016.                             {
  1017.                                 PSTR pmethod = p;
  1018.  
  1019.                                 BOOL fClass = TRUE;
  1020.  
  1021.                                 while (*p != ',' && *p != '\0')
  1022.                                 {
  1023.                                     if (*p == '(')
  1024.                                         fClass = FALSE;
  1025.                                     p++;
  1026.                                 }
  1027.  
  1028.                                 CHAR origch = *p;
  1029.                                 *p = '\0';
  1030.  
  1031.                                 PSTR **ppArray;
  1032.                                 ULONG *pCount;
  1033.  
  1034.                                 if (fClass)
  1035.                                 {
  1036.                                     ppArray = &m_ClassesToHook;
  1037.                                     pCount = &m_nClassesToHook;
  1038.                                 }
  1039.                                 else
  1040.                                 {
  1041.                                     ppArray = &m_MethodsToHook;
  1042.                                     pCount = &m_nMethodsToHook;
  1043.                                 }
  1044.  
  1045.                                 if (GrowStringArray(ppArray, pCount))
  1046.                                     (*ppArray)[*pCount - 1] = pmethod;
  1047.  
  1048.                                 if (origch == '\0')
  1049.                                     break;
  1050.                                 p++;
  1051.                             }
  1052.                         }
  1053.                     }
  1054.                 }
  1055.             }
  1056.         }
  1057.  
  1058.         RegCloseKey(hknm);
  1059.     }
  1060.  
  1061.     m_pszClass = _strdup(pclass_file_name);
  1062.  
  1063.     Spew("Monitoring %s.\n", m_pszClass ? m_pszClass : "UNKNOWN CLASS");
  1064.  
  1065.     *prequested_events = m_dwEvents;
  1066.  
  1067.     if (RegisterDefineClassHook(&DefineClassStart, &DefineClassDone))
  1068.         m_dwFlags |= SEMF_REGISTERED_CLASS_LOADER_HOOK;
  1069.  
  1070.     BOOL first = TRUE;
  1071.  
  1072.     Spew("Current state:");
  1073.  
  1074. #define SPEWSTATE(flag,descr) \
  1075.     if ((java_flags & (flag)) != 0) \
  1076.     { \
  1077.         if (!first) \
  1078.             Spew(","); \
  1079.         else \
  1080.             first = FALSE; \
  1081.         Spew(" " descr); \
  1082.     }
  1083.  
  1084.     SPEWSTATE(JVM_STATE_INTERPRETER_ENABLED, "Interpreter loop");
  1085.     SPEWSTATE(JVM_STATE_FAST_INTERPRETER_ENABLED, "Fast interpreter loop");
  1086.     SPEWSTATE(JVM_STATE_JIT_COMPILER_ENABLED, "JIT compiler");
  1087.     SPEWSTATE(JVM_STATE_DEBUGGER_ENABLED, "Debugging");
  1088.  
  1089. #undef SPEWSTATE
  1090.  
  1091.     Spew("\n");
  1092.  
  1093.     if (m_monitor_info2 != NULL)
  1094.     {
  1095.         LPSTR pszClassPath;
  1096.         hr = m_monitor_info2->GetClassPath(&pszClassPath);
  1097.         if (hr == S_OK)
  1098.         {
  1099.             Spew("class path: %s\n", pszClassPath);
  1100.         
  1101.             CoTaskMemFree(pszClassPath);
  1102.         }
  1103.  
  1104.         DWORD states;               // bit mask of flags from JAVA_STATE_FLAGS
  1105.         DWORD categories;           // bit mask of flags from JAVA_EVENT_CATEGORY
  1106.         JAVA_EXECUTION_MODEL LastModel;
  1107.         JVM_EVENT_TYPE LastType;
  1108.         JVM_EVENT_TYPE2 LastType2;
  1109.         hr = m_monitor_info2->GetProfilingCapabilities(
  1110.             &states,
  1111.             &categories,
  1112.             &LastModel,
  1113.             &LastType,
  1114.             &LastType2);
  1115.         if (hr == S_OK)
  1116.         {
  1117.             Spew("Supported states (%xh):", states);
  1118.             BOOL first = TRUE;
  1119. #define SPEWSTATE(flag,descr) \
  1120.             if ((states & (flag)) != 0) \
  1121.             { \
  1122.                 if (!first) \
  1123.                     Spew(","); \
  1124.                 else \
  1125.                     first = FALSE; \
  1126.                 Spew(" " descr); \
  1127.             }
  1128.  
  1129.             SPEWSTATE(JVM_STATE_INTERPRETER_ENABLED, "Interpreter loop");
  1130.             SPEWSTATE(JVM_STATE_FAST_INTERPRETER_ENABLED, "Fast interpreter loop");
  1131.             SPEWSTATE(JVM_STATE_JIT_COMPILER_ENABLED, "JIT compiler");
  1132.             SPEWSTATE(JVM_STATE_DEBUGGER_ENABLED, "Debugging");
  1133.  
  1134. #undef SPEWSTATE
  1135.             Spew("\n");
  1136.  
  1137.             Spew("Supported categories:");
  1138. #define SPEWCAT(flag) \
  1139.             if ((categories & flag) != 0) \
  1140.                 Spew(" " #flag)
  1141.  
  1142.             SPEWCAT(JVM_MONITOR_NONE);
  1143.             SPEWCAT(JVM_MONITOR_CLASS_LOADS);
  1144.             SPEWCAT(JVM_MONITOR_METHOD_CALLS);
  1145.             SPEWCAT(JVM_MONITOR_JIT_COMPILATION);
  1146.             SPEWCAT(JVM_MONITOR_BYTE_CODE_EXECUTION);
  1147.             SPEWCAT(JVM_MONITOR_SOURCE_LINE_EXECUTION);
  1148.             SPEWCAT(JVM_MONITOR_EXCEPTIONS);
  1149.             SPEWCAT(JVM_MONITOR_MONITOR_OPERATIONS);
  1150.             SPEWCAT(JVM_MONITOR_GARBAGE_COLLECTIONS);
  1151.             SPEWCAT(JVM_MONITOR_THREADS);
  1152.             SPEWCAT(JVM_MONITOR_SAMPLING);
  1153.             SPEWCAT(JVM_MONITOR_EXCEPTION_UNWIND);
  1154.  
  1155. #undef SPEWCAT
  1156.             Spew("\n");
  1157.  
  1158.             Spew("Last supported execution model: %d\n", LastModel);
  1159.  
  1160.             Spew("Last supported NotifyEvent type: %d\n", LastType);
  1161.  
  1162.             Spew("Last supported NotifyEvent2 type: %d\n", LastType2);
  1163.         }
  1164.     }
  1165.  
  1166.     if (m_HeapMonitor)
  1167.     {
  1168.         hr = InstallHeapMonitorCallbacks(TRUE);
  1169.  
  1170.         DWORD caps;
  1171.         HRESULT hr2 = m_HeapMonitor->ModifyHeapMonitorCapabilities(JVM_HEAPMON_OBJECT_AGE, TRUE, &caps);
  1172.         if (FAILED(hr2) || !(caps & JVM_HEAPMON_OBJECT_AGE))
  1173.             Spew("Failed to enable object aging.\n");
  1174.     }
  1175.     else if (m_dwHeapDumpFlags)
  1176.         Spew("VM does not support heap monitors.\n");
  1177.     
  1178.     if (m_dwSamplingFrequency > 0)
  1179.     {
  1180.         DWORD tid;
  1181.         m_hSamplerThread = CreateThread(NULL, 0, &SamplerThreadEntry, this, 0, &tid);
  1182.         if (m_hSamplerThread != INVALID_HANDLE_VALUE)
  1183.             Spew("Sampler thread %x\n", tid);
  1184.         else
  1185.         {
  1186.             hr = HRESULT_FROM_WIN32(GetLastError());
  1187.             ASSERT(FAILED(hr));
  1188.             return hr;
  1189.         }
  1190.     }
  1191.  
  1192.     if (m_monitor_info4 != NULL)
  1193.     {
  1194.         m_monitor_info4->SetMonitorInitializationOptions(  JVM_INIT_OPT_GC_SAFE_METHOD_CALLS
  1195.                                                          | JVM_INIT_OPT_WONT_TOGGLE_METHOD_CALL_EVENTS);
  1196.     }
  1197.  
  1198.     return(hr);
  1199. }
  1200.  
  1201. STDMETHODIMP SampleEventMonitor::NotifyEvent(JVM_EVENT_TYPE event, UniqueID event_id)
  1202. {
  1203.     HRESULT hr;
  1204.  
  1205.     switch (event)
  1206.     {
  1207.         // Execution events
  1208.         case JVM_EVENT_TYPE_EXCEPTION_OCCURRED:     // An exception occurred.  The exception handler will be executed in StackID.
  1209.         {
  1210.             InterlockedIncrement((LONG*)&m_NumExceptionsThrown);
  1211.             Spew("Exception thrown.  Handler is in StackID %xh.\n", event_id);
  1212.             break;
  1213.         }
  1214.  
  1215.         // thread events
  1216.         case JVM_EVENT_TYPE_THREAD_CREATE:          // A Java threadID is being created (ThreadID created)
  1217.         {
  1218.             DWORD dwWin32ThreadID;
  1219.  
  1220.             if (m_monitor_info2)
  1221.             {
  1222.                 hr = m_monitor_info2->ThreadInformation(event_id, &dwWin32ThreadID);
  1223.  
  1224.                 if (hr == S_OK)
  1225.                     Spew("ThreadID %xh created.  Win32 thread ID %lxh.\n",
  1226.                          event_id,
  1227.                          dwWin32ThreadID);
  1228.                 else
  1229.                     Spew("IJavaEventMonitorIDInfo2::ThreadInformation() failed for ThreadID %xh during JVM_EVENT_TYPE_THREAD_CREATE, returning %lxh.\n",
  1230.                          event_id,
  1231.                          hr);
  1232.             }
  1233.             else
  1234.                 Spew("ThreadID %xh created.\n",
  1235.                      event_id);
  1236.  
  1237.             m_ThreadRecords.AddThread((ThreadID)event_id, dwWin32ThreadID);
  1238.  
  1239.             break;
  1240.         }
  1241.         
  1242.         case JVM_EVENT_TYPE_THREAD_DESTROY:         // A Java threadID is being destroyed (ThreadID destroyed)
  1243.             if (m_monitor_info2)
  1244.             {
  1245.                 DWORD dwWin32ThreadID;
  1246.  
  1247.                 hr = m_monitor_info2->ThreadInformation(event_id, &dwWin32ThreadID);
  1248.  
  1249.                 if (hr == S_OK)
  1250.                     Spew("ThreadID %xh destroyed.  Win32 thread ID %lxh.\n",
  1251.                          event_id,
  1252.                          dwWin32ThreadID);
  1253.                 else
  1254.                     Spew("IJavaEventMonitorIDInfo2::ThreadInformation() failed for ThreadID %xh during JVM_EVENT_TYPE_THREAD_DESTROY, returning %lxh.\n",
  1255.                          event_id,
  1256.                          hr);
  1257.             }
  1258.             else
  1259.                 Spew("ThreadID %xh destroyed.\n",
  1260.                      event_id);
  1261.  
  1262.             m_ThreadRecords.RemoveThread((ThreadID)event_id);
  1263.  
  1264.             break;
  1265.  
  1266.         // Class loading
  1267.         case JVM_EVENT_TYPE_CLASS_LOAD_STARTED:     // A class is being loaded (PSTR)
  1268.             Spew("Loading class %s...\n", (PCSTR)event_id);
  1269.             if (m_monitor_info2 != NULL)
  1270.             {
  1271.                 EnterCriticalSection(&m_cs);
  1272.                 {
  1273.                     hr = m_monitor_info2->GetStackTrace(NULL);
  1274.                     if (FAILED(hr))
  1275.                         Spew("(stack trace not available)\n");
  1276.                 }
  1277.                 LeaveCriticalSection(&m_cs);
  1278.             }
  1279.             break;
  1280.         case JVM_EVENT_TYPE_CLASS_LOAD_FINISHED:    // A class has been loaded (ClassID)
  1281.         {
  1282.             m_NumClassesLoaded++;
  1283.  
  1284.             if (m_VMRelease > VM_IE40)
  1285.             {
  1286.                 PSTR pszClassName;
  1287.                 PSTR pszSrcFile;
  1288.                 int ncMethods;
  1289.                 MethodID *pmethodid;
  1290.  
  1291.                 hr = m_monitor_info->ClassInformation(event_id, &pszClassName, &pszSrcFile, &ncMethods, &pmethodid, NULL);
  1292.  
  1293.                 if (hr == S_OK)
  1294.                 {
  1295.                     int i;
  1296.  
  1297.                     Spew("Loaded class %s as ClassID %xh compiled from source file %s.\n",
  1298.                          pszClassName,
  1299.                          event_id,
  1300.                          pszSrcFile ? pszSrcFile : "<unknown>");
  1301.  
  1302.                     for (i = 0; i < m_nClassesToHook; i++)
  1303.                     {
  1304.                         if (strcmp(pszClassName, m_ClassesToHook[i]) == 0)
  1305.                         {
  1306.                             Spew("Hooking all methods in class %s\n", pszClassName);
  1307.                             hr = m_monitor_info3->EnableMethodCallEvents(event_id, JVM_ID_CLASS, JVM_PERMIT_METHOD_CALL_EVENTS);
  1308.                             break;
  1309.                         }
  1310.                     }
  1311.  
  1312.                     for (i = 0; i < ncMethods; i++)
  1313.                     {
  1314.                         PSTR pszMethodName;
  1315.                         int ncSrcLines;
  1316.                         SourceLineInfo *pSrcLineInfo;
  1317.  
  1318.                         hr = m_monitor_info->MethodInformation(pmethodid[i], &pszMethodName, NULL, NULL, &ncSrcLines, &pSrcLineInfo);
  1319.  
  1320.                         if (hr == S_OK)
  1321.                         {
  1322.                             Spew("    %s\n",
  1323.                                  pszMethodName);
  1324.  
  1325.                             if (ncSrcLines > 0)
  1326.                             {
  1327.                                 Spew("        Source line mapping information for %d source lines:\n",
  1328.                                      ncSrcLines);
  1329.  
  1330.                                 for (int iLine = 0; iLine < ncSrcLines; iLine++)
  1331.                                     Spew("            bytecode offset %lu -> source line %lu\n",
  1332.                                          pSrcLineInfo[iLine].code_offset,
  1333.                                          pSrcLineInfo[iLine].line_number);
  1334.                             }
  1335.                             else
  1336.                                 Spew("        No source line mapping information.\n");
  1337.  
  1338.                             for (ULONG iMethod = 0; iMethod < m_nMethodsToHook; iMethod++)
  1339.                             {
  1340.                                 if (strcmp(pszMethodName, m_MethodsToHook[iMethod]) == 0)
  1341.                                 {
  1342.                                     Spew("Hooking method %s\n", pszMethodName);
  1343.                                     hr = m_monitor_info3->EnableMethodCallEvents(pmethodid[i], JVM_ID_METHOD, JVM_PERMIT_METHOD_CALL_EVENTS);
  1344.                                     break;
  1345.                                 }
  1346.                             }
  1347.  
  1348.                             CoTaskMemFree(pszMethodName);
  1349.                             pszMethodName = NULL;
  1350.  
  1351.                             CoTaskMemFree(pSrcLineInfo);
  1352.                             pSrcLineInfo = NULL;
  1353.                         }
  1354.                         else
  1355.                             Spew("CNullEventMonitor::NotifyEvent(): IJavaEventMonitorIDInfo::MethodInformation() failed for MethodID %xh during JVM_EVENT_TYPE_JIT_COMPILE_FINISHED, returning %lxh.\n",
  1356.                                  event_id,
  1357.                                  hr);
  1358.                     }
  1359.  
  1360.                     if (m_monitor_info2)
  1361.                     {
  1362.                         DWORD StaticDataSize;
  1363.                         DWORD InstanceSize;
  1364.                         hr = m_monitor_info2->StaticClassInformation(event_id, &StaticDataSize, &InstanceSize);
  1365.                         if (hr == S_OK)
  1366.                         {
  1367.                             Spew("%s: static data size %d, instance size %d\n", pszClassName, StaticDataSize, InstanceSize);
  1368.                         }
  1369.                     }
  1370.  
  1371.                     if (m_monitor_info3 != NULL)
  1372.                     {
  1373.                         ClassID idSuperclass;
  1374.                         unsigned nInterfaces;
  1375.                         ClassID *rgidInterfaces;
  1376.                         unsigned nMethods;
  1377.                         MethodID *rgidMethods;
  1378.  
  1379.                         hr = m_monitor_info3->ClassInformation2(
  1380.                                 event_id, &idSuperclass,
  1381.                                 &rgidInterfaces, &nInterfaces,
  1382.                                 &rgidMethods, &nMethods);
  1383.  
  1384.                         if (hr == S_OK)
  1385.                         {
  1386.                             int i;
  1387.  
  1388.                             if (idSuperclass != NULL)
  1389.                             {
  1390.                                 PSTR pszSuperclassName;
  1391.                                 hr = m_monitor_info->ClassInformation(idSuperclass, &pszSuperclassName, NULL, NULL, NULL, NULL);
  1392.                                 if (hr == S_OK)
  1393.                                 {
  1394.                                     Spew("Superclass of %s is %s.\n", pszClassName, pszSuperclassName);
  1395.  
  1396.                                     CoTaskMemFree(pszSuperclassName);
  1397.                                 }
  1398.                                 else
  1399.                                 {
  1400.                                     Spew("Unable to obtain name of superclass of %s.\n", pszClassName);
  1401.                                 }
  1402.                             }
  1403.                             else
  1404.                             {
  1405.                                 Spew("Class %s has no superclass.\n", pszClassName);
  1406.                             }
  1407.  
  1408.                             Spew("Class %s implements %u interfaces.\n", pszClassName, nInterfaces);
  1409.                             for (i = 0; i < nInterfaces; i++)
  1410.                             {
  1411.                                 Spew("interface %u: ", i);
  1412.  
  1413.                                 PSTR pszInterfaceName;
  1414.                                 hr = m_monitor_info->ClassInformation(rgidInterfaces[i], &pszInterfaceName, NULL, NULL, NULL, NULL);
  1415.                                 if (hr == S_OK)
  1416.                                 {
  1417.                                     Spew("%s\n", pszInterfaceName);
  1418.  
  1419.                                     CoTaskMemFree(pszInterfaceName);
  1420.                                 }
  1421.                                 else
  1422.                                 {
  1423.                                     Spew("<unable to obtain interface name>\n");
  1424.                                 }
  1425.                             }
  1426.  
  1427.                             Spew("Class %s implements %u methods.\n", pszClassName, nMethods);
  1428.                             for (i = 0; i < nMethods; i++)
  1429.                             {
  1430.                                 Spew("method %u: ", i);
  1431.  
  1432.                                 PSTR pszMethodName;
  1433.                                 hr = m_monitor_info->MethodInformation(rgidMethods[i], &pszMethodName, NULL, NULL, NULL, NULL);
  1434.                                 if (hr == S_OK)
  1435.                                 {
  1436.                                     Spew("%s\n", pszMethodName);
  1437.  
  1438.                                     CoTaskMemFree(pszMethodName);
  1439.                                 }
  1440.                                 else
  1441.                                 {
  1442.                                     Spew("<unable to obtain method name>\n");
  1443.                                 }
  1444.                             }
  1445.  
  1446.                             CoTaskMemFree(rgidInterfaces);
  1447.                             CoTaskMemFree(rgidMethods);
  1448.                         }
  1449.                         else
  1450.                             Spew("CNullEventMonitor::NotifyEvent(): IJavaEventMonitorIDInfo::ClassInformation2() failed for ClassID %xh during JVM_EVENT_TYPE_CLASS_LOAD_FINISHED, returning %lxh.\n",
  1451.                                  event_id,
  1452.                                  hr);
  1453.                     }
  1454.  
  1455.                     CoTaskMemFree(pszClassName);
  1456.                     CoTaskMemFree(pszSrcFile);
  1457.                     CoTaskMemFree(pmethodid);
  1458.                 }
  1459.                 else
  1460.                     Spew("CNullEventMonitor::NotifyEvent(): IJavaEventMonitorIDInfo::ClassInformation() failed for ClassID %xh during JVM_EVENT_TYPE_CLASS_LOAD_FINISHED, returning %lxh.\n",
  1461.                          event_id,
  1462.                          hr);
  1463.             }
  1464.  
  1465.             break;
  1466.         }
  1467.         case JVM_EVENT_TYPE_CLASS_UNLOAD:           // A class has been unloaded (ClassID)
  1468.         {
  1469.             if (m_VMRelease > VM_IE40)
  1470.             {
  1471.                 PSTR pszClassName;
  1472.  
  1473.                 hr = m_monitor_info->ClassInformation(event_id, &pszClassName, NULL, NULL, NULL, NULL);
  1474.  
  1475.                 if (hr == S_OK)
  1476.                 {
  1477.                     Spew("Unloaded class %s as ClassID %xh.\n",
  1478.                          pszClassName,
  1479.                          event_id);
  1480.  
  1481.                     CoTaskMemFree(pszClassName);
  1482.                     pszClassName = NULL;
  1483.                 }
  1484.                 else
  1485.                     Spew("CNullEventMonitor::NotifyEvent(): IJavaEventMonitorIDInfo::ClassInformation() failed for ClassID %xh during JVM_EVENT_TYPE_CLASS_UNLOAD, returning %lxh.\n",
  1486.                          event_id,
  1487.                          hr);
  1488.             }
  1489.  
  1490.             break;
  1491.         }
  1492.  
  1493.         // method JIT compilation
  1494.         case JVM_EVENT_TYPE_JIT_COMPILE_STARTED:    // Starting to JIT-compile method MethodID.
  1495.             m_NumJITStarts++;
  1496.             break;
  1497.         case JVM_EVENT_TYPE_JIT_COMPILE_FINISHED:   // Finished JIT-compiling method MethodID.
  1498.         {
  1499.             PSTR method_name;
  1500.             ClassID clsid;
  1501.             JAVA_EXECUTION_MODEL jem;
  1502.             int ncSrcLines;
  1503.             SourceLineInfo *pSrcLineInfo;
  1504.  
  1505.             m_NumJITStops++;
  1506.  
  1507.             hr = m_monitor_info->MethodInformation(event_id, &method_name, &clsid, &jem, &ncSrcLines, &pSrcLineInfo);
  1508.  
  1509.             if (hr == S_OK)
  1510.             {
  1511.                 int i;
  1512.  
  1513.                 Spew("    %s JIT-compiled\n",
  1514.                      method_name);
  1515.  
  1516.                 if (ncSrcLines > 0)
  1517.                 {
  1518.                     Spew("        Source line mapping information for %d source lines:\n",
  1519.                          ncSrcLines);
  1520.  
  1521.                     for (i = 0; i < ncSrcLines; i++)
  1522.                         Spew("            JIT-compiled code offset %lu -> source line %lu\n",
  1523.                              pSrcLineInfo[i].code_offset,
  1524.                              pSrcLineInfo[i].line_number);
  1525.                 }
  1526.                 else
  1527.                     Spew("        No source line mapping information.\n");
  1528.  
  1529.                 CoTaskMemFree(method_name);
  1530.                 method_name = NULL;
  1531.  
  1532.                 if (pSrcLineInfo)
  1533.                 {
  1534.                     CoTaskMemFree(pSrcLineInfo);
  1535.                     pSrcLineInfo = NULL;
  1536.                 }
  1537.             }
  1538.             else
  1539.                 Spew("CNullEventMonitor::NotifyEvent(): IJavaEventMonitorIDInfo::MethodInformation() failed for MethodID %xh during JVM_EVENT_TYPE_JIT_COMPILE_FINISHED, returning %lxh.\n",
  1540.                      event_id,
  1541.                      hr);
  1542.  
  1543.             break;
  1544.         }
  1545.  
  1546.         // Garbage collection
  1547.         case JVM_EVENT_TYPE_GC_STARTED:         // The garbage collector started (no ID)
  1548.             break;
  1549.  
  1550.         case JVM_EVENT_TYPE_GC_FINISHED:        // The garbage collector stopped (no ID)
  1551.             m_NumGCs++;
  1552.             break;
  1553.  
  1554.         // Shutdown events
  1555.         case JVM_EVENT_TYPE_SHUTDOWN:           // Program exiting (no ID).
  1556.             m_fVMTerminated = TRUE;
  1557.             Spew("Shutting down (%u)\n",         (UINT)event);
  1558.             Spew("  Method calls:                %8u\n", m_NumMethodCalls);
  1559.             Spew("  Method returns:              %8u\n", m_NumMethodReturns);
  1560.             Spew("  Byte codes executed:         %8u\n", m_NumByteCodesExecuted);
  1561.             Spew("  Exceptions thrown:           %8u\n", m_NumExceptionsThrown);
  1562.             Spew("  Methods JIT compiled:        %8u\n", m_NumJITStops);
  1563.             Spew("  Methods not JIT compiled:    %8u\n", m_NumJITStarts - m_NumJITStops);
  1564.             Spew("  Monitors entered:            %8u\n", m_NumMonitorsEntered);
  1565.             Spew("  Classes loaded:              %8u\n", m_NumClassesLoaded);
  1566.             Spew("  Garbage collections:         %8u\n", m_NumGCs);
  1567.             break;
  1568.  
  1569.         default:
  1570.             // What is this?
  1571.             break;
  1572.     }
  1573.  
  1574.     return S_OK;
  1575. }
  1576.  
  1577.  
  1578. HRESULT SampleEventMonitor::SpewStackFrame (
  1579.         PCSTR pszOperation,
  1580.         MethodID method_id,
  1581.         StackID stack_id)
  1582. {
  1583.     HRESULT hr;
  1584.     PSTR method_name;
  1585.     ClassID class_id;
  1586.     JAVA_EXECUTION_MODEL jem;
  1587.  
  1588.     hr = m_monitor_info->MethodInformation(method_id, &method_name, &class_id, &jem, NULL, NULL);
  1589.  
  1590.     if (hr == S_OK)
  1591.     {
  1592.         PCSTR pcszExecModel;
  1593.  
  1594.         switch (jem)
  1595.         {
  1596.             case JVM_EXECUTION_JIT_COMPILED:
  1597.                 pcszExecModel = "JIT-compiled";
  1598.                 break;
  1599.  
  1600.             case JVM_EXECUTION_NATIVE:
  1601.                 pcszExecModel = "native";
  1602.                 break;
  1603.  
  1604.             case JVM_EXECUTION_INTERPRETED:
  1605.                 pcszExecModel = "interpreted";
  1606.                 break;
  1607.  
  1608.             case JVM_EXECUTION_FAST_INTERPRETED:
  1609.                 pcszExecModel = "fast interpreted";
  1610.                 break;
  1611.  
  1612.             case JVM_EXECUTION_COM:
  1613.                 pcszExecModel = "COM";
  1614.                 break;
  1615.  
  1616.             default:
  1617.                 pcszExecModel = "UNKNOWN";
  1618.                 break;
  1619.         }
  1620.  
  1621.         PrintStackLeader();
  1622.         Spew("%s %lxh %s [%s]",
  1623.                 pszOperation,
  1624.                 stack_id,
  1625.                 method_name,
  1626.                 pcszExecModel);
  1627.  
  1628.         if (method_name)
  1629.         {
  1630.             CoTaskMemFree(method_name);
  1631.             method_name = NULL;
  1632.         }
  1633.     }
  1634.  
  1635.     return(hr);
  1636. }
  1637.  
  1638. VOID SampleEventMonitor::SpewValue (CHAR chsig, PVOID pvalue)
  1639. {
  1640.     INT i;
  1641.     
  1642.     switch (chsig)
  1643.     {
  1644.     case '[':
  1645.     case 'L':
  1646.         {
  1647.             ObjectID objid = *(ObjectID*)pvalue;
  1648.             if (objid == NULL)
  1649.             {
  1650.                 Spew("null");
  1651.             }
  1652.             else
  1653.             {
  1654.                 ClassID clsid;
  1655.                 HRESULT hr = m_monitor_info->ObjectInformation(objid, &clsid);
  1656.                 if (hr == S_OK)
  1657.                 {
  1658.                     PSTR pszclsname;
  1659.                     hr = m_monitor_info->ClassInformation(clsid, &pszclsname, NULL, NULL, NULL, NULL);
  1660.                     if (hr == S_OK)
  1661.                     {
  1662.                         Spew("%s", pszclsname);
  1663.  
  1664.                         CoTaskMemFree(pszclsname);
  1665.                     }
  1666.                 }
  1667.             }
  1668.         }
  1669.         break;
  1670.         
  1671.     case 'Z':
  1672.         Spew("%s", *(BOOL*)pvalue ? "true" : "false");
  1673.         break;
  1674.  
  1675.     case 'C':
  1676.         Spew("%lc", *(WCHAR*)pvalue);
  1677.         break;
  1678.  
  1679.     case 'J':
  1680.         Spew("%I64d", *(__int64*)pvalue);
  1681.         break;
  1682.  
  1683.     case 'D':
  1684.         Spew("%lg", *(double*)pvalue);
  1685.         break;
  1686.  
  1687.     case 'F':
  1688.         Spew("%g", *(float*)pvalue);
  1689.         break;
  1690.  
  1691.     case 'B':
  1692.         i = *(BYTE*)pvalue;
  1693.         goto PRINT_INT;
  1694.         
  1695.     case 'S':
  1696.         i = *(SHORT*)pvalue;
  1697.         goto PRINT_INT;
  1698.         
  1699.     case 'I':
  1700.         i = *(INT*)pvalue;
  1701.     PRINT_INT:
  1702.         Spew("%d", i);
  1703.         break;
  1704.  
  1705.     case 'V':
  1706.         break;
  1707.     }
  1708. }
  1709.  
  1710. int NextSigElement (PSTR *ppszsig)
  1711. {
  1712.     int nslots = 1;
  1713.     PSTR psznext = *ppszsig;
  1714.     CHAR chsig = *psznext;
  1715.     if (chsig == 'L')
  1716.     {
  1717.     findsigend:
  1718.         psznext = strchr(psznext, ';');
  1719.     }
  1720.     else if (chsig == '[')
  1721.     {
  1722.         while (1)
  1723.         {
  1724.             chsig = *psznext;
  1725.             if (chsig != '[')
  1726.                 break;
  1727.             psznext++;
  1728.         }
  1729.         if (chsig == 'L')
  1730.             goto findsigend;
  1731.     }
  1732.     else if (chsig == 'J' || chsig == 'D')
  1733.     {
  1734.         nslots = 2;
  1735.     }
  1736.     *ppszsig = psznext+1;
  1737.     return nslots;
  1738. }
  1739.  
  1740. STDMETHODIMP SampleEventMonitor::MethodEntry (MethodID method_id, StackID stack_id)
  1741. {
  1742.     PSTR method_name;
  1743.     SpewStackFrame("Entering", method_id, stack_id);
  1744.  
  1745.     if (m_monitor_info3 != NULL)
  1746.     {
  1747.         DWORD *pparams;
  1748.         JVM_CALLING_CONVENTION callconv;
  1749.         DWORD flags;
  1750.         HRESULT hr = m_monitor_info3->GetMethodEntryParameters(&pparams, NULL, &callconv, &flags);
  1751.         if (hr == S_OK)
  1752.         {
  1753.             PSTR pszMethodName;
  1754.             hr = m_monitor_info->MethodInformation(method_id, &pszMethodName, NULL, NULL, NULL, NULL);
  1755.             if (hr == S_OK)
  1756.             {
  1757.                 if (callconv == JVM_CALL_PASCAL)
  1758.                 {
  1759.                     PSTR pszsig = strchr(pszMethodName, '(')+1;
  1760.  
  1761.                     Spew(" (");
  1762.  
  1763.                     PSTR pszsigtmp = pszsig;
  1764.                     int totalparamslots = 0;
  1765.                     while (*pszsigtmp != ')')
  1766.                         totalparamslots += NextSigElement(&pszsigtmp);
  1767.  
  1768.                     if (totalparamslots)
  1769.                     {
  1770.                         pparams += totalparamslots;
  1771.  
  1772.                         pszsigtmp = pszsig;
  1773.                         do
  1774.                         {
  1775.                             if (pszsigtmp != pszsig)
  1776.                                 Spew(", ");
  1777.  
  1778.                             CHAR chvalsig = *pszsigtmp;
  1779.  
  1780.                             pparams -= NextSigElement(&pszsigtmp);
  1781.  
  1782.                             SpewValue(chvalsig, pparams);
  1783.                         }
  1784.                         while (*pszsigtmp != ')');
  1785.                     }
  1786.  
  1787.                     Spew(")");
  1788.  
  1789.                     if (flags & JVM_CALL_THIS)
  1790.                     {
  1791.                         Spew(" this=");
  1792.                         SpewValue('L', pparams + totalparamslots);
  1793.                     }
  1794.                 }
  1795.  
  1796.                 CoTaskMemFree(pszMethodName);
  1797.             }
  1798.         }
  1799.     }
  1800.  
  1801.     Spew("\n");
  1802.  
  1803.     m_NumMethodCalls++;
  1804.  
  1805.     return S_OK;
  1806. }
  1807.  
  1808. STDMETHODIMP SampleEventMonitor::MethodExit(StackID stack_id)
  1809. {
  1810.     m_NumMethodReturns++;
  1811.  
  1812.     PrintStackLeader();
  1813.     Spew("Exiting to %lxh\n", stack_id);
  1814.     
  1815.     return S_OK;
  1816. }
  1817.  
  1818. STDMETHODIMP SampleEventMonitor::ExecuteByteCode(MethodID method_id, BYTE_CODE *pbyte_code, DWORD byte_code_offset)
  1819. {
  1820.     m_NumByteCodesExecuted++;
  1821.  
  1822.     return S_OK;
  1823. }
  1824.  
  1825. STDMETHODIMP SampleEventMonitor::ExecuteSourceLine(MethodID method_id, DWORD line_number)
  1826. {
  1827.     // Currently not implemented by vm.
  1828.  
  1829.     return(S_OK);
  1830. }
  1831.  
  1832. // IJavaEventMonitor2 methods
  1833.  
  1834. STDMETHODIMP SampleEventMonitor::NotifyEvent2(JVM_EVENT_TYPE2 event2, UniqueID first_event_id, UniqueID second_event_id)
  1835. {
  1836.     HRESULT hr = S_OK;
  1837.  
  1838.     switch (event2)
  1839.     {
  1840.         // thread events
  1841.  
  1842.         case JVM_EVENT_TYPE2_THREAD_SET_NAME:       // The given thread's name has been set to the given Unicode string.
  1843.             Spew("Thread %lxh's name is \"%ls\".\n",
  1844.                  first_event_id,
  1845.                  (PWSTR)second_event_id);
  1846.             break;
  1847.  
  1848.         // Execution events
  1849.  
  1850.         case JVM_EVENT_TYPE2_EXCEPTION_THROWN:      // An exception is about to be thrown.  ID1 is the ClassID of the exception.
  1851.         {
  1852.             PSTR pszExceptionClassName;
  1853.             hr = m_monitor_info->ClassInformation((ClassID)first_event_id, &pszExceptionClassName, NULL, NULL, NULL, NULL);
  1854.             if (hr == S_OK)
  1855.             {
  1856.                 Spew("Exception %s is about to be thrown.\n", pszExceptionClassName);
  1857.  
  1858.                 CoTaskMemFree(pszExceptionClassName);
  1859.             }
  1860.         }
  1861.         
  1862.         case JVM_EVENT_TYPE2_EXCEPTION_OCCURRED:     // An exception occurred.  ID1 is MethodID, ID2 is StackID.  The exception handler will be executed in MethodID/StackID's stack frame.
  1863.         {
  1864.             m_NumExceptionsThrown++;
  1865.             Spew("Exception thrown.  Handler is in MethodID %xh, StackID %xh.\n",
  1866.                  first_event_id, second_event_id);
  1867.  
  1868.             break;
  1869.         }
  1870.  
  1871.         case JVM_EVENT_TYPE2_EXCEPTION_UNWIND:
  1872.             break;
  1873.  
  1874.         // stack trace
  1875.         case JVM_EVENT_TYPE2_STACK_TRACE:
  1876.             SpewStackFrame("Stack trace", (MethodID)first_event_id, (StackID)second_event_id);
  1877.             Spew("\n");
  1878.             break;
  1879.  
  1880.         case JVM_EVENT_TYPE2_INITIALIZED:
  1881.             m_fVMInitialized = TRUE;
  1882.             break;
  1883.     }
  1884.  
  1885.     return(hr);
  1886. }
  1887.  
  1888.  
  1889. STDMETHODIMP SampleEventMonitor::MethodExit2(MethodID method_id, StackID stack_id)
  1890. {
  1891.     if (stack_id == NULL)
  1892.     {
  1893.         PrintStackLeader();
  1894.         Spew("Exiting to top level.");
  1895.     }
  1896.     else
  1897.     {
  1898.         SpewStackFrame("Exiting to", method_id, stack_id);
  1899.     }
  1900.  
  1901.     if (m_monitor_info3 != NULL)
  1902.     {
  1903.         HRESULT hr;
  1904.         MethodID returning_method_id;
  1905.         __int64 *pval;
  1906.         
  1907.         hr = m_monitor_info3->GetMethodExitReturnValue(&returning_method_id, &pval);
  1908.         if (hr == S_OK)
  1909.         {
  1910.             PSTR pszMethodName;
  1911.             hr = m_monitor_info->MethodInformation(returning_method_id, &pszMethodName, NULL, NULL, NULL, NULL);
  1912.             if (hr == S_OK)
  1913.             {
  1914.                 CHAR *pchretsig = strchr(pszMethodName, ')')+1;
  1915.                 if (*pchretsig != 'V')
  1916.                 {
  1917.                     Spew(", returning ");
  1918.                 
  1919.                     SpewValue(*pchretsig, pval);
  1920.                 }
  1921.             
  1922.                 CoTaskMemFree(pszMethodName);
  1923.             }
  1924.         }
  1925.     }
  1926.  
  1927.     Spew("\n");
  1928.  
  1929.     m_NumMethodReturns++;
  1930.  
  1931.     return(S_OK);
  1932. }
  1933.  
  1934.  
  1935. STDMETHODIMP SampleEventMonitor::GetPossibleEventCategories (DWORD *ppossible_events)
  1936. {
  1937.     *ppossible_events = m_dwEvents;
  1938.     return(S_OK);
  1939. }
  1940.  
  1941.  
  1942. // IHeapInfoCallback
  1943.  
  1944. STDMETHODIMP SampleEventMonitor::BeginContainer(CONTAINER_TYPE type, UniqueID id1, UniqueID id2)
  1945. {
  1946.     HRESULT hr;
  1947.  
  1948.     // Display a description of the container.  An efficient profiler
  1949.     // implementation will cache these if it chooses to use them.
  1950.  
  1951.     PWSTR descr;
  1952.     hr = m_HeapMonitor->GetContainerDescription(type, &descr, NULL);
  1953.     if (SUCCEEDED(hr))
  1954.     {
  1955.         Spew("Object references from %ls", descr);
  1956.         switch (type)
  1957.         {
  1958.         case C_BEGIN:
  1959.             m_fInHeap = FALSE;
  1960.             m_fMoreRefs = FALSE;
  1961.             m_iField = 0;
  1962.             break;
  1963.  
  1964.         case C_RT_THREAD:
  1965.         case C_RT_NATIVEGC:
  1966.         case C_RT_INTERNALFRAME:
  1967.             Spew(" 0x%x", id1);
  1968.             break;
  1969.  
  1970.         case C_RT_JIT:
  1971.         case C_RT_NATIVE:
  1972.         case C_RT_INTERPRETED: {
  1973.             ClassID cls;
  1974.             PSTR methname;
  1975.             hr = m_monitor_info->MethodInformation((MethodID)id2, &methname, &cls, NULL, NULL, NULL);
  1976.             if (SUCCEEDED(hr))
  1977.             {
  1978.                 Spew(" 0x%x %s", id1, methname);
  1979.             }
  1980.             break; }
  1981.  
  1982.         case C_RT_CLASS: {
  1983.             PSTR clsname;
  1984.             hr = m_monitor_info->ClassInformation((ClassID)id1, &clsname, NULL, NULL, NULL, NULL);
  1985.             if (SUCCEEDED(hr))
  1986.             {
  1987.                 Spew(" %s", clsname);
  1988.             }
  1989.             break; }
  1990.  
  1991.         case C_HEAP:
  1992.             m_fInHeap = TRUE;
  1993.         }
  1994.         Spew(":\n");
  1995.  
  1996.         hr = S_OK;
  1997.     }
  1998.  
  1999.     return(hr);
  2000. }
  2001.  
  2002. VOID SampleEventMonitor::DumpRef (ObjectID objid, DWORD objflags)
  2003. {
  2004.     Spew("%08x", objid);
  2005.  
  2006.     if (objid)
  2007.     {
  2008.         if (objflags & JVM_OBJ_ALREADY_REPORTED)
  2009.         {
  2010.             Spew(" (reported)");
  2011.         }
  2012.  
  2013.         if (objflags & JVM_OBJ_ALREADY_VISITED)
  2014.             Spew(" (visited)");
  2015.     }
  2016.     
  2017.     Spew("\n");
  2018. }
  2019.  
  2020. STDMETHODIMP SampleEventMonitor::RootReferences (const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
  2021. {
  2022.     for (unsigned i = 0; i < nrefs; i++)
  2023.     {
  2024.         Spew("from root: ");
  2025.         DumpRef(prefs[i], pflags[i]);
  2026.     }
  2027.  
  2028.     return S_OK;
  2029. }
  2030.  
  2031. STDMETHODIMP SampleEventMonitor::ObjectReferences (ObjectID id, DWORD flags, const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
  2032. {
  2033.     HRESULT hr;
  2034.  
  2035.     ASSERT(!(flags & JVM_OBJ_ALREADY_VISITED));
  2036.  
  2037.     ClassID clstype;
  2038.     hr = m_monitor_info->ObjectInformation(id, &clstype);
  2039.     if (EVAL(SUCCEEDED(hr)))
  2040.     {
  2041.         DWORD age = 0;
  2042.         EVAL(m_HeapMonitor->GetObjectAge(id, &age) == S_OK);
  2043.     
  2044.         if (!(flags & JVM_OBJ_MORE_REFERENCES))
  2045.         {
  2046.             DWORD size;
  2047.             EVAL(m_monitor_info2->GetObjectSize(id, &size) == S_OK);
  2048.         }
  2049.  
  2050.         PSTR clsname;
  2051.         hr = m_monitor_info->ClassInformation(clstype, &clsname, NULL, NULL, NULL, NULL);
  2052.         if (EVAL(SUCCEEDED(hr)))
  2053.         {
  2054.             Spew("%08x %s", id, clsname);
  2055.  
  2056.             DWORD size;
  2057.             hr = m_monitor_info2->GetObjectSize(id, &size);
  2058.             if (EVAL(SUCCEEDED(hr)))
  2059.                 Spew(" (%u bytes)", size);
  2060.  
  2061.             PWSTR descr;
  2062.             HRESULT hr2 = m_monitor_info2->DescribeObject(id, &descr);
  2063.             if (SUCCEEDED(hr2) && descr)
  2064.             {
  2065.                 Spew(" %ls", descr);
  2066.                 
  2067.                 CoTaskMemFree(descr);
  2068.             }
  2069.  
  2070.             if (!(flags & JVM_OBJ_ALREADY_REPORTED))
  2071.                 Spew(" (not reported from roots)");
  2072.  
  2073.             if (m_fMoreRefs)
  2074.                 Spew(" (continued)");
  2075.  
  2076.             Spew("\n");
  2077.  
  2078.             // - for some Strings, nfields > nrefs
  2079.             // - empty arrays may be reported
  2080.             if (nrefs)
  2081.             {
  2082.                 if (clsname[0] != '[')
  2083.                 {
  2084.                     if (EVAL(m_monitor_info2 != NULL))
  2085.                     {
  2086.                         // TODO: cache field list
  2087.  
  2088.                         unsigned nfields;
  2089.                         FieldID *pfields;
  2090.                         hr = m_monitor_info2->GetClassFields(
  2091.                             clstype,
  2092.                             &nfields,
  2093.                             &pfields);
  2094.                         if (SUCCEEDED(hr))
  2095.                         {
  2096.                             unsigned ifld = m_iField;
  2097.                             unsigned iref = 0;
  2098.                             while (ifld < nfields)
  2099.                             {
  2100.                                 PSTR name;
  2101.                                 DWORD flags;
  2102.                                 hr = m_monitor_info2->FieldInformation(pfields[ifld], &name, &flags);
  2103.                                 ifld++;
  2104.                                 if (!EVAL(SUCCEEDED(hr)))
  2105.                                     break;
  2106.                                     
  2107.                                 if (!(flags & JVM_FIELD_STATIC) && (flags & JVM_FIELD_OBJECTREF))
  2108.                                 {
  2109.                                     Spew("\t%-23s ", name);
  2110.  
  2111.                                     DumpRef(prefs[iref], pflags[iref]);
  2112.                                     
  2113.                                     iref++;
  2114.                                     if (iref == nrefs)
  2115.                                         break;
  2116.                                 }
  2117.                             }
  2118.  
  2119.                             m_iField = ifld;
  2120.                         }
  2121.                     }
  2122.                     else
  2123.                         hr = E_FAIL;
  2124.                 }
  2125.                 else
  2126.                 {
  2127.                     unsigned i;
  2128.                     for (i = 0; i < nrefs; i++)
  2129.                     {
  2130.                         Spew("\t%3d ", m_iField+i);
  2131.                         
  2132.                         DumpRef(prefs[i], pflags[i]);
  2133.                     }
  2134.                     m_iField += nrefs;
  2135.                 }
  2136.             }
  2137.  
  2138.             m_fMoreRefs = ((flags & JVM_OBJ_MORE_REFERENCES) != 0);
  2139.             if (!m_fMoreRefs)
  2140.                 m_iField = 0;
  2141.         }
  2142.     }
  2143.     
  2144.     if (SUCCEEDED(hr))
  2145.     {
  2146.         // Profilers may control the traversal by returning S_OK or
  2147.         // S_POSTPONE_REFERENCES.  S_OK continues to traverse references
  2148.         // through this object that were not marked with JVM_OBJ_ALREADY_VISITED.
  2149.         // S_POSTPONE_REFERENCES postpones reporting these referenced objects
  2150.         // until the C_HEAP container.
  2151.  
  2152.         hr = (m_dwFlags & SEMF_TRAVERSE_REFERENCES) ? S_OK : S_POSTPONE_REFERENCES;
  2153.     }
  2154.  
  2155.     return(hr);
  2156. }
  2157.  
  2158. STDMETHODIMP SampleEventMonitor::OnObjectAllocated (ObjectID id, ClassID type)
  2159. {
  2160.     HRESULT hr;
  2161.  
  2162.     ClassID clstype;
  2163.     hr = m_monitor_info->ObjectInformation(id, &clstype);
  2164.     if (EVAL(SUCCEEDED(hr)))
  2165.     {
  2166.         ASSERT(clstype == type);
  2167.         
  2168.         PSTR clsname;
  2169.         hr = m_monitor_info->ClassInformation(clstype, &clsname, NULL, NULL, NULL, NULL);
  2170.         if (EVAL(SUCCEEDED(hr)))
  2171.         {
  2172.             Spew("object allocated: %08x %s\n", id, clsname);
  2173.  
  2174.             EnterCriticalSection(&m_cs);
  2175.             {
  2176.                 hr = m_monitor_info2->GetStackTrace(NULL);
  2177.                 if (FAILED(hr))
  2178.                     Spew("(stack trace not available)\n");
  2179.  
  2180.                 DWORD size;
  2181.                 hr = m_monitor_info2->GetObjectSize(id, &size);
  2182.                 ASSERT(SUCCEEDED(hr));
  2183.             }
  2184.             LeaveCriticalSection(&m_cs);
  2185.         }
  2186.     }
  2187.  
  2188.     return(hr);
  2189. }
  2190.  
  2191.  
  2192. HRESULT SampleEventMonitor::InstallHeapMonitorCallbacks (BOOL fEnable)
  2193. {
  2194.     HRESULT hr = S_OK;
  2195.  
  2196.     if (m_dwFlags & SEMF_REGISTERED_HEAP_CALLBACK)
  2197.     {
  2198.         EVAL(m_HeapMonitor->GetHeapInfo(NULL) == S_OK);
  2199.         m_dwFlags &= ~SEMF_REGISTERED_HEAP_CALLBACK;
  2200.     }
  2201.  
  2202.     if (fEnable && (m_dwFlags & SEMF_HEAP_DUMP))
  2203.     {
  2204.         IHeapInfoCallback *heapcb;
  2205.         hr = QueryInterface(IID_IHeapInfoCallback, (PVOID*)&heapcb);
  2206.         if (EVAL(hr == S_OK))
  2207.         {
  2208.             if (EVAL(m_HeapMonitor->GetHeapInfo(heapcb) == S_OK))
  2209.                 m_dwFlags |= SEMF_REGISTERED_HEAP_CALLBACK;
  2210.         }
  2211.     }
  2212.  
  2213.     if (m_dwFlags & SEMF_REGISTERED_ALLOC_CALLBACK)
  2214.     {
  2215.         EVAL(m_HeapMonitor->NotifyOnObjectAllocations(NULL) == S_OK);
  2216.         m_dwFlags &= SEMF_REGISTERED_ALLOC_CALLBACK;
  2217.     }
  2218.  
  2219.     if (fEnable && (m_dwFlags & SEMF_OBJECT_ALLOCATIONS))
  2220.     {
  2221.         IObjectAllocationCallback *alloccb;
  2222.         hr = QueryInterface(IID_IObjectAllocationCallback, (PVOID*)&alloccb);
  2223.         if (EVAL(hr == S_OK))
  2224.         {
  2225.             if (EVAL(m_HeapMonitor->NotifyOnObjectAllocations(alloccb) == S_OK))
  2226.                 m_dwFlags |= SEMF_REGISTERED_ALLOC_CALLBACK;
  2227.         }
  2228.     }
  2229.  
  2230.     return hr;
  2231. }
  2232.  
  2233. VOID SampleEventMonitor::SpewSample (JVM_METHOD_SAMPLE *psample)
  2234. {
  2235.     if (psample->accuracy == JVM_SAMPLE_NONE)
  2236.     {
  2237.         Spew(" (none)\n");
  2238.     }
  2239.     else
  2240.     {
  2241.         Spew(" %3u%% %8x %8x ", psample->accuracy, psample->ip, psample->sp);
  2242.  
  2243.         if (psample->flags & JVM_SAMPLE_LOCATION)
  2244.         {
  2245.             char locch = '?';
  2246.             switch (psample->location_type)
  2247.             {
  2248.             case JVM_LOCATION_UNKNOWN:
  2249.                 locch = 'x';
  2250.                 break;
  2251.             case JVM_LOCATION_JIT:
  2252.                 locch = 'j';
  2253.                 break;
  2254.             case JVM_LOCATION_NATIVE:
  2255.                 locch = 'n';
  2256.                 break;
  2257.             case JVM_LOCATION_GC:
  2258.                 locch = 'g';
  2259.                 break;
  2260.             case JVM_LOCATION_COMPILER:
  2261.                 locch = 'c';
  2262.                 break;
  2263.             case JVM_LOCATION_LOADER:
  2264.                 locch = 'l';
  2265.                 break;
  2266.             case JVM_LOCATION_DEBUGGER:
  2267.                 locch = 'd';
  2268.                 break;
  2269.             case JVM_LOCATION_SECURITY:
  2270.                 locch = 'y';
  2271.                 break;
  2272.             case JVM_LOCATION_PROFILER:
  2273.                 locch = 'p';
  2274.                 break;
  2275.             case JVM_LOCATION_BLOCKING:
  2276.                 locch = 'w';
  2277.                 break;
  2278.             }
  2279.  
  2280.             Spew(" %c", locch);
  2281.         }
  2282.  
  2283.         if (psample->flags & JVM_SAMPLE_GENERATED_CODE)
  2284.             Spew(" (generated)");
  2285.  
  2286.         if (psample->flags & JVM_SAMPLE_METHOD_ID)
  2287.             SpewStackFrame("", psample->method_id, psample->stack_id);
  2288.  
  2289.         Spew("\n");
  2290.     }
  2291. }
  2292.  
  2293.  
  2294. //static
  2295. DWORD WINAPI SampleEventMonitor::SamplerThreadEntry (LPVOID lpThreadParameter)
  2296. {
  2297.     return ((SampleEventMonitor*)lpThreadParameter)->SamplerThread();
  2298. }
  2299.  
  2300. DWORD SampleEventMonitor::SamplerThread ()
  2301. {
  2302.     HRESULT hr;
  2303.     JVM_METHOD_SAMPLE sample;
  2304.  
  2305.     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  2306.  
  2307.     while (!m_fVMTerminated)
  2308.     {
  2309.         Sleep(m_dwSamplingFrequency);
  2310.         if (!m_fVMInitialized)
  2311.             continue;
  2312.  
  2313.         Spew("%u threads\n", m_ThreadRecords.GetNumThreads());
  2314.  
  2315.         {
  2316.             ThreadRecordEnumerator e(&m_ThreadRecords);
  2317.  
  2318.             ThreadID vmid;
  2319.             while (e.Next(&vmid))
  2320.             {
  2321.                 sample.flags = m_dwSampleFlags;
  2322.                 hr = m_monitor_info2->SampleThreadLocation(vmid, &sample);
  2323.                 if (SUCCEEDED(hr))
  2324.                 {
  2325.                     Spew("%8x", vmid);
  2326.                     SpewSample(&sample);
  2327.                 }
  2328.             }
  2329.         }
  2330.         
  2331.         __int64 nmonitors;
  2332.         if (EVAL(m_monitor_info->GetMonitorUsage(&nmonitors) == S_OK))
  2333.         {
  2334.             Spew("monitors in use: %I64u\n", nmonitors);
  2335.         }
  2336.     }
  2337.  
  2338.     return 0;
  2339. }
  2340.  
  2341.