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

  1. // hpmonmgr.cpp
  2. //
  3. // Created 10/04/98
  4. //
  5. // (C)Copyright 1998-1999 Microsoft Corporation, All rights reserved.
  6. //
  7.  
  8. #include "pch.hpp"
  9. #pragma hdrstop
  10.  
  11. #include "guids.h"
  12. #include "hpmonmgr.hpp"
  13. #include "heapview.hpp"
  14. #include "clsview.hpp"
  15. #include "resource.h"
  16. #include "obsearch.hpp"
  17. #include "utf8.hpp"
  18. #include "objlist.hpp"
  19. #include "gcview.hpp"
  20.  
  21. // main.cpp
  22. extern ULONG g_ModuleRefCount;
  23.  
  24.  
  25. //
  26. // ------------------------------------------------------------------------
  27. // Synchronization
  28. //
  29. // - profiler events may be received from the VM on any thread.  This thread
  30. // may be one of our ui threads if a VM api called from the ui thread
  31. // generates an event.
  32. // - some ui elements will contain IDWrappers as lParams.  Use of these IDs on
  33. // the ui thread needs to be serialized with their destruction on some other
  34. // thread.
  35. // - when a client window is destroyed, its IHeapMonitorClient needs to be
  36. // revoked.  Dispatch of messages from random event threads needs to be
  37. // serialized with removing the client from the list.
  38. //
  39. // A UniqueID from the VM becomes invalid upon returning from the event
  40. // callback notifying the monitor that the ID is becoming invalid.  UI threads
  41. // may already be making use of the ID, so the monitor must stall the event
  42. // thread until the UI thread has completed all uses of the ID.  This means
  43. // that communication between event threads and ui threads must be synchronous
  44. // (use SendMessage).  Further, because events may be generated on ui threads
  45. // while events are being handled on other threads, no locks needed by event
  46. // handling may be held across the SendMessage.  The VM does not hold locks
  47. // across event dispatch that may be needed on other threads to service an
  48. // IJavaEventMonitorIDInfo[n] call.  Use of IDs on the UI thread needs to be
  49. // serialized with use on non-UI threads - while on the UI thread, it is safe
  50. // to hold a lock around messaging since it will be serviced on the same
  51. // thread.
  52. //
  53. // Note that the VM ensures that it is not possible for an event to be received
  54. // that refers to an ID for which a creation event is simultaneously being
  55. // sent.  The second event will not be dispatched until the event callback for
  56. // the first event has returned.  This form of out-of-order event processing is
  57. // not possible.  For the purposes of this sample, creation events are handled
  58. // synchronously, just like destruction events, so that it is impossible to
  59. // handle a destruction event before a creation event.
  60. //
  61. // Note that although out-of-order events are not possible, IDs may be
  62. // discovered for which creation events have not been received.  Class
  63. // load/unload events are not fully implemented for all class types in the
  64. // current VM.
  65. //
  66. // Also, due to a bug in the VM, thread destruction event reporting is not
  67. // serialized with heap dumping.  The VM may report thread containers for
  68. // threads that have not yet been reported to the monitor or have just been
  69. // destroyed, and thread destruction events may be sent on another thread while
  70. // a heap dump is in progress.  (Since gc is using the thread, obviously the
  71. // thread can't really be destroyed, and in fact it really isn't.  Only the
  72. // reporting of this event is messed up.  Sorry.)  This is the one exception
  73. // where an id can be used beyond its destruction event: if the destruction
  74. // event for a thread id is received while a heap dump is in progress, the
  75. // thread id may be safely used until returning from the C_END notification.
  76. //
  77. // Another oddity: a IHeapInfoCallback cannot be revoked asynchronously.  It
  78. // must be revoked during a heap dump, or during a JVM_EVENT_TYPE_GC_STARTED
  79. // or JVM_EVENT_TYPE_GC_FINISHED event.
  80. //
  81. // Synchronization with window closing is handled by BasicClient::WndProc.
  82. //
  83. // 
  84. // ------------------------------------------------------------------------
  85. // Heap exploration
  86. //
  87. // HeapMonitorManager performs a "flat" traversal of the heap.  The VM reports
  88. // all roots first, and by returning S_POSTPONE_REFERENCES for each root, all
  89. // objects will be visitied within the C_HEAP container.  This provides clients
  90. // with a quick view of what is to come.
  91. //
  92. // Once all roots and their references are known, the heap may be explored
  93. // manually using IJavaEventMonitorIDInfo2::GetObjectField and
  94. // IJavaEventMonitorIDInfo2::GetArrayElement.  Manual exploration requires
  95. // hashing all objects to know when an object has been re-discovered (to
  96. // identify cycles and objects with multiple references).  The VM specifies
  97. // which objects have already been reported - this alone (see exception below)
  98. // indicates objects with multiple references, so only these objects need to
  99. // be hashed.  Typically these objects are a small percentage of total number
  100. // of objects, substantially reducing the amount of storage needed to safely
  101. // navigate the heap.
  102. //
  103. // Heap exploration may take a long time, so clients may simultaneously explore
  104. // objects manually.  Any objects discovered in this manner must be hashed.
  105. // Since clients must follow objects starting from roots, if they run into a
  106. // cycle, they will necessarily have caused all of the nodes in the cycle to be
  107. // hashed.  Once heap enumeration is complete, all objects with multiple
  108. // references are known, so no further hashing is required.
  109. //
  110. // For exploration that may touch the entire heap, clients should wait until
  111. // enumeration completes, then request the heap dump thread to call
  112. // IJavaHeapMonitor2::WalkHeap (ex. see HeapMonitorManager::SearchHeap, which
  113. // is used by ClassInstancesViewer and ObjectReferencesViewer).
  114. //
  115. // IJavaEventMonitorIDInfo2::GetObjectField and
  116. // IJavaEventMonitorIDInfo2::GetArrayElement are used for manual exploration.
  117. // In VM builds older than 3223, these apis had some bugs:
  118. // - with object aging enabled, GetObjectField might return invalid fields of
  119. // some variable size classes
  120. // - with object aging enabled, GetArrayElement might return an invalid
  121. // element past the end of the array
  122. // - for arrays of objects, GetArrayElement might return an invalid element
  123. // past the end of the array
  124. // To work around these bugs, during heap dumping, record the actual number of
  125. // references for instances of variable-size classes and for arrays of
  126. // objects, and use this to limit the number of reference fields or elements
  127. // retrieved from the object.  This sample does not demonstrate this.
  128. //
  129. //
  130. // ------------------------------------------------------------------------
  131. // Detecting cycles
  132. //
  133. // The JVM_OBJ_ALREADY_REPORTED flag indicates an object with multiple
  134. // references, which indicates a potential cycle.  If S_OK is always returned
  135. // from both ObjectReferences and RootReferences, then a depth-first traversal
  136. // is performed and this bit is always accurate.  A reference will be reported
  137. // for an object before the object is visited, i.e. JVM_OBJ_ALREADY_VISITED
  138. // will never be set for an object without JVM_OBJ_ALREADY_REPORTED also set.
  139. //
  140. // If S_POSTPONE_REFERENCES is ever returned, then if an object is visited
  141. // before any of its references, JVM_OBJ_ALREADY_REPORTED will be set for the
  142. // first reference.  This is because the VM considers visiting an act of
  143. // reporting, so that self-referencing objects can be detected.
  144. //
  145. // There are two ways to deal with this:
  146. //
  147. // 1. always return S_OK.  However, always returning S_POSTPONE_REFERENCES is a
  148. // slightly faster way to simply find all objects.
  149. //
  150. // 2. detect when an object is visited but not yet reported.  This means both
  151. // JVM_OBJ_ALREADY_VISITED and JVM_OBJ_ALREADY_REPORTED will be clear for the
  152. // object in ObjectReferences.  Hash the object and remember this condition.
  153. // When the first reference to this object is discovered, via RootReferences or
  154. // ObjectReferences, pretend the JVM_OBJ_ALREADY_REPORTED flag is clear.  For
  155. // subsequent references, JVM_OBJ_ALREADY_REPORTED will always be correctly set.
  156. //
  157. // Example:
  158. //
  159. // Reference order:  root -> A -> B -> A
  160. // C_HEAP reporting order:  B, A
  161. //
  162. // In S_OK-always mode, nodes are traversed in reference order:
  163. //
  164. // 1. root refers to A (!VISITED && !REPORTED).  A is marked REPORTED.
  165. // 2. A (!VISITED && REPORTED) refers to B (!VISITED && !REPORTED).  A is marked VISITED.  B is marked REPORTED.
  166. // 3. B (!VISITED && REPORTED) refers to A (VISITED && REPORTED).  B is marked VISITED.
  167. //
  168. // In S_POSTPONE_REFERENCES-always mode, nodes are reported in the C_HEAP
  169. // container in arbitrary order, with all roots reported first:
  170. //
  171. // 1. root refers to A (!VISITED && !REPORTED).  A is marked REPORTED.
  172. // 2. B (!VISITED && !REPORTED) refers to A (!VISITED && REPORTED).  B is marked VISITED and REPORTED.
  173. //                   =========
  174. // 3. A (!VISITED && REPORTED) refers to B (VISITED && REPORTED).  A is marked VISITED.
  175. //                                                     ========
  176. //
  177.  
  178.  
  179. //static
  180. CRITICAL_SECTION HeapMonitorManager::s_mgrlistcs;
  181. //static
  182. HeapMonitorManager *HeapMonitorManager::s_mgrlist = NULL;
  183. //static
  184. HICON HeapMonitorManager::s_htrayicon;
  185.  
  186.  
  187. //------------------------------------------------------------------------
  188.  
  189.  
  190. BOOL HeapMonitorManager::RegisterClient (IHeapMonitorClient *newclient, HeapMonitorClientRegistrationInfo *pinfo)
  191. {
  192.     ASSERT(!(pinfo->StoppedEventMask & HMC_NON_GC_EVENTS));
  193.  
  194.     BOOL ret;
  195.  
  196.     ClientRecord *rec = new(ClientRecord());
  197.     ret = (rec != NULL);
  198.     if (ret)
  199.     {
  200.         Enter();
  201.         {
  202.             rec->next = m_clients;
  203.             m_clients = rec;
  204.  
  205.             (rec->client = newclient)->AddRef();
  206.             rec->refcount = 1;
  207.  
  208.             rec->EventMask = pinfo->EventMask | HMC_UNMASKABLE_EVENTS;
  209.             rec->InfoMask = pinfo->InfoMask | GetInfoNeededForEvents(pinfo->EventMask);
  210.  
  211.             m_EventMaskUnion |= rec->EventMask;
  212.             m_InfoMaskUnion |= rec->InfoMask;
  213.  
  214.             rec->StoppedEventMask = pinfo->StoppedEventMask | HMC_UNMASKABLE_EVENTS;
  215.             rec->StoppedInfoMask = pinfo->StoppedInfoMask | GetInfoNeededForEvents(pinfo->StoppedEventMask);
  216.  
  217.             m_StoppedEventMaskUnion |= rec->StoppedEventMask;
  218.             m_StoppedInfoMaskUnion |= rec->StoppedInfoMask;
  219.         }
  220.         Leave();
  221.     }
  222.  
  223.     // Clients don't get events for already-existing ids.  Presumably they
  224.     // can catch up in a more efficient manner by fetching them all in a
  225.     // clump...this entire process needs to be atomic.
  226.  
  227.     return ret;
  228. }
  229.  
  230.  
  231. VOID HeapMonitorManager::UnregisterClient (IHeapMonitorClient *deadclient)
  232. {
  233.     Enter();
  234.     {
  235.         DWORD NewEventMaskUnion = 0;
  236.         DWORD NewInfoMaskUnion = 0;
  237.         DWORD NewStoppedEventMaskUnion = 0;
  238.         DWORD NewStoppedInfoMaskUnion = 0;
  239. #ifdef DEBUG
  240.         BOOL fFound = FALSE;
  241. #endif // DEBUG
  242.  
  243.         ClientRecord **prev = &m_clients;
  244.         for (;;)
  245.         {
  246.             ClientRecord *cur = *prev;
  247.             if (cur != NULL)
  248.             {
  249.                 if (cur->client == deadclient)
  250.                 {
  251. #ifdef DEBUG
  252.                     ASSERT(!fFound);
  253.                     fFound = TRUE;
  254. #endif // DEBUG
  255.  
  256.                     deadclient->Release();
  257.                     if ((--cur->refcount) == 0)
  258.                     {
  259.                         *prev = cur->next;
  260.                         delete(cur);
  261.                         continue;
  262.                     }
  263.                 }
  264.  
  265.                 NewEventMaskUnion |= cur->EventMask;
  266.                 NewInfoMaskUnion |= cur->InfoMask;
  267.                 NewStoppedEventMaskUnion |= cur->StoppedEventMask;
  268.                 NewStoppedInfoMaskUnion |= cur->StoppedInfoMask;
  269.  
  270.                 prev = &cur->next;
  271.             }
  272.             else
  273.             {
  274.                 break;
  275.             }
  276.         }
  277.  
  278.         ASSERT(fFound);
  279.  
  280.         m_EventMaskUnion = NewEventMaskUnion;
  281.         m_InfoMaskUnion = NewInfoMaskUnion;
  282.         m_StoppedEventMaskUnion = NewStoppedEventMaskUnion;
  283.         m_StoppedInfoMaskUnion = NewStoppedInfoMaskUnion;
  284.     }
  285.     Leave();
  286. }
  287.  
  288.  
  289. VOID HeapMonitorManager::IterateClients (DWORD mask, CLIENTITERFN *cb, PVOID token)
  290. {
  291.     ASSERT(!Entered());
  292.  
  293.     // Bump the refcount of the record of each client we will notify.  If
  294.     // new clients appear while we're sending notifications, we need to
  295.     // take care not to adjust their refcounts.  New clients are added at
  296.     // the head of the list, so we addref everything from the current head,
  297.     // remember the current head, and release everything from the saved
  298.     // head.
  299.  
  300.     ClientRecord *first;
  301.     ClientRecord *cur;
  302.     
  303.     Enter();
  304.     {
  305.         first = m_clients;
  306.         if (!first)
  307.         {
  308. bail:
  309.             Leave();
  310.             return;
  311.         }
  312.  
  313.         if (!IsEventRequested(mask))
  314.         {
  315.             goto bail;
  316.         }
  317.  
  318.         cur = first;
  319.         do
  320.         {
  321.             cur->refcount++;
  322.             cur->client->AddRef();
  323.  
  324.             cur = cur->next;
  325.         }
  326.         while (cur != NULL);
  327.     }
  328.     Leave();
  329.  
  330.     cur = first;
  331.     do
  332.     {
  333.         if (   (cur->EventMask & mask)
  334.             || (m_flags & HMM_FL_STOPPED) && (cur->StoppedEventMask & mask))
  335.         {
  336.             (*cb)(cur->client, token);
  337.         }
  338.  
  339.         cur = cur->next;
  340.     }
  341.     while (cur != NULL);
  342.  
  343.     Enter();
  344.     {
  345.         ClientRecord **pprev = &first;
  346.         for (;;)
  347.         {
  348.             cur = *pprev;
  349.             if (cur != NULL)
  350.             {
  351.                 cur->client->Release();
  352.                 if ((--cur->refcount) > 0)
  353.                 {
  354.                     pprev = &cur->next;
  355.                 }
  356.                 else
  357.                 {
  358.                     // Rare case: a client was removed while we were
  359.                     // notifying it.  If it was the first client we
  360.                     // notified, re-check the head list to see if any new
  361.                     // clients were added.  If so, find the one linked to
  362.                     // the removed client.
  363.  
  364.                     if (pprev == &first)
  365.                     {
  366.                         if (first == m_clients)
  367.                         {
  368.                             pprev = &m_clients;
  369.                         }
  370.                         else
  371.                         {
  372.                             ClientRecord *prev = m_clients;
  373.                             for (;;)
  374.                             {
  375.                                 ClientRecord *next = prev->next;
  376.                                 if (next == cur)
  377.                                     break;
  378.                                 prev = next;
  379.                             }
  380.                             pprev = &prev->next;
  381.                         }
  382.                     }
  383.  
  384.                     *pprev = cur->next;
  385.                     delete(cur);
  386.                 }
  387.             }
  388.             else
  389.             {
  390.                 break;
  391.             }
  392.         }
  393.     }
  394.     Leave();
  395. }
  396.  
  397.  
  398. //------------------------------------------------------------------------
  399.  
  400.  
  401. //static
  402. DWORD WINAPI HeapMonitorManager::HeapMonitorManagerMessagePumpThread (PVOID token)
  403. {
  404.     HeapMonitorManager *hmm = (HeapMonitorManager*)token;
  405.  
  406.     if (hmm->InitializeUI())
  407.     {
  408.         MSG msg;
  409.         while (GetMessage(&msg, (HWND) NULL, 0, 0))
  410.         {
  411.             // Don't have any accelerators.
  412.             //if (   !TranslateMDISysAccel(m_mdi, &msg)
  413.             //    && !TranslateAccelerator(m_hwnd, m_accel, &msg))
  414.             {
  415.                 TranslateMessage(&msg);
  416.                 DispatchMessage(&msg);
  417.             }
  418.         }
  419.     }
  420.  
  421.     return 0;
  422. }
  423.  
  424.  
  425. BOOL HeapMonitorManager::InitializeUI ()
  426. {
  427.     BOOL result;
  428.  
  429.     InitCommonControls();
  430.  
  431.     result = (m_hmnu = LoadMenu(m_hinst, MAKEINTRESOURCE(IDR_MAINMENU))) != NULL;
  432.  
  433.     if (result)
  434.     {
  435.         result = (m_hmnuWindow = GetSubMenu(m_hmnu, 1)) != NULL;
  436.     }
  437.  
  438.     HICON hmainicon = NULL;
  439.     if (result)
  440.     {
  441.         result = (hmainicon = LoadIcon(m_hinst, MAKEINTRESOURCE(IDI_MAINICON))) != NULL;
  442.     }
  443.  
  444.     if (result)
  445.     {
  446.         result = (m_ProgressIndicatorImages = ImageList_LoadImage(
  447.                 m_hinst,
  448.                 MAKEINTRESOURCE(IDB_HEAPDUMP_PROGRESS),
  449.                 16,
  450.                 0,
  451.                 CLR_DEFAULT,
  452.                 IMAGE_BITMAP,
  453.                 LR_LOADTRANSPARENT)) != NULL;
  454.     }
  455.  
  456.     if (result)
  457.     {
  458.         WNDCLASS wc;
  459.         ZeroMemory(&wc, sizeof(wc));
  460.         wc.lpfnWndProc = &WndProc;
  461.         wc.hInstance = m_hinst;
  462.         wc.hIcon = hmainicon;
  463.         wc.lpszClassName = WC_HEAPMONITOR;
  464.         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  465.         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  466.         result = RegisterClass(&wc);
  467.     }
  468.  
  469.     if (result)
  470.     {
  471.         result = CreateWindowEx( 
  472.             0,
  473.             WC_HEAPMONITOR ,
  474.             "Java Heap Monitor",
  475.             WS_OVERLAPPEDWINDOW | WS_MINIMIZE,
  476.             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  477.             NULL,
  478.             m_hmnu,
  479.             m_hinst,
  480.             this) != NULL;
  481.     }
  482.  
  483.     if (result)
  484.     {
  485.         ShowWindow(m_hwnd, SW_HIDE);
  486.  
  487.         result = AddTrayIcon();
  488.     }
  489.  
  490.     return result;
  491. }
  492.  
  493.  
  494. VOID HeapMonitorManager::DestroyNow ()
  495. {
  496.     ASSERT(m_flags & HMM_FL_CLOSED);
  497.  
  498.     Enter();
  499.     {
  500.         if (!(m_flags & HMM_FL_DESTRUCTION_PENDING))
  501.         {
  502.             // No more events, please.
  503.             m_vminfo->SetEventMask(0);
  504.  
  505.             // No more heap dumps, please.
  506.             m_vmheapmon->GetHeapInfo(NULL);
  507.  
  508.             SendNotifyMessage(m_hwnd, HMM_WM_DESTROY_NOW, 0, 0);
  509.  
  510.             m_flags |= HMM_FL_DESTRUCTION_PENDING;
  511.         }
  512.     }
  513.     Leave();
  514. }
  515.  
  516.  
  517. VOID HeapMonitorManager::RedrawMenuBar ()
  518. {
  519.     RedrawWindow(m_hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
  520. }
  521.  
  522.  
  523. BOOL HeapMonitorManager::GrayMenu (UINT idm)
  524. {
  525.     ASSERT(CanSendUIMessages());
  526.     
  527.     BOOL result;
  528.  
  529.     MENUITEMINFO mii;
  530.     mii.cbSize = sizeof(mii);
  531.     mii.fMask = MIIM_STATE;
  532.     mii.fState = MFS_GRAYED;
  533.  
  534.     result = SetMenuItemInfo(m_hmnu, idm, FALSE, &mii);
  535.     if (result)
  536.         RedrawMenuBar();
  537.  
  538.     return result;
  539. }
  540.  
  541.  
  542. BOOL HeapMonitorManager::ChangeMenuTextAndUngray (UINT idm, PCSTR text)
  543. {
  544.     ASSERT(CanSendUIMessages());
  545.  
  546.     BOOL result;
  547.  
  548.     MENUITEMINFO mii;
  549.     mii.cbSize = sizeof(mii);
  550.     mii.fMask = MIIM_STATE | MIIM_TYPE;
  551.     mii.fType = MFT_STRING;
  552.     mii.dwTypeData = (PSTR)text;
  553.     mii.cch = strlen(text);
  554.     mii.fState = 0;
  555.  
  556.     result = SetMenuItemInfo(m_hmnu, idm, FALSE, &mii);
  557.     if (result)
  558.         RedrawMenuBar();
  559.  
  560.     return result;
  561. }
  562.  
  563.  
  564. // Called in response to selecting the 'Go' or 'Stop' menu.
  565. VOID HeapMonitorManager::StopOrGo ()
  566. {
  567.     Enter();
  568.     {
  569.         if (!(m_flags & (HMM_FL_STOP | HMM_FL_STOPPED)))
  570.         {
  571.             // Gray the "Stop!" item, and request a heap dump.
  572.  
  573.             if (GrayMenu(IDM_STOPGO))
  574.             {
  575.                 m_flags |= HMM_FL_STOP;
  576.             }
  577.         }
  578.         else if (m_flags & HMM_FL_STOPPED)
  579.         {
  580.             // Gray the "Go!" item, and resume VM execution.
  581.  
  582.             if (GrayMenu(IDM_STOPGO))
  583.             {
  584.                 m_flags |= HMM_FL_GO;
  585.                 
  586.                 SetEvent(m_hresumeevt);
  587.             }
  588.         }
  589.     }
  590.     Leave();
  591. }
  592.  
  593.  
  594. VOID HeapMonitorManager::IndicateStopped ()
  595. {
  596.     ASSERT(m_flags & HMM_FL_STOPPED);
  597.  
  598.     // Un-gray the "Stop!" item, and change its text to "Go!".
  599.  
  600.     ChangeMenuTextAndUngray(IDM_STOPGO, "Go!");
  601. }
  602.  
  603. VOID HeapMonitorManager::IndicateRunning ()
  604. {
  605.     ASSERT(!(m_flags & (HMM_FL_STOP | HMM_FL_STOPPED)));
  606.  
  607.     // Un-gray the "Go!" item, and change its text to "Stop!".
  608.  
  609.     ChangeMenuTextAndUngray(IDM_STOPGO, "Stop!");
  610. }
  611.  
  612.  
  613. // static
  614. VOID CALLBACK HeapMonitorManager::UpdateProgressIndicator(
  615.   HWND hwnd,     // handle to window
  616.   UINT uMsg,     // WM_TIMER message
  617.   UINT idEvent,  // timer identifier
  618.   DWORD dwTime   // current system time
  619. )
  620. {
  621.     HeapMonitorManager *hmm = (HeapMonitorManager*)GetWindowLong(hwnd, GWL_USERDATA);
  622.  
  623.     if (   hmm->m_ProgressIndicator != hmm->m_LastProgressIndicator
  624.         || hmm->m_gcinfo.nObjects != hmm->m_LastObjectCount)
  625.     {
  626.         hmm->m_LastProgressIndicator = hmm->m_ProgressIndicator;
  627.         hmm->m_LastObjectCount = hmm->m_gcinfo.nObjects;
  628.     
  629.         hmm->m_iProgressIndicatorImage = (hmm->m_iProgressIndicatorImage + 1) % 9;
  630.  
  631.         RedrawWindow(hmm->m_status, NULL, NULL, RDW_INVALIDATE);
  632.     }
  633. }
  634.  
  635.  
  636. BOOL HeapMonitorManager::StartHeapDumpProgressIndicatorWorker ()
  637. {
  638.     BOOL fSuccess = FALSE;
  639.  
  640.     Enter();
  641.     {
  642.         ASSERT(!(m_flags & HMM_FL_PROGRESS_INDICATOR));
  643.  
  644.         INT rgPartRightEdges[2] = { 16, -1 };
  645.         if (SendMessage(m_status, SB_SETPARTS, ARRAY_ELEMENTS(rgPartRightEdges), (LPARAM)&rgPartRightEdges[0]))
  646.         {
  647.             if (SendMessage(m_status, SB_SETTEXT, SBT_OWNERDRAW, 0))
  648.             {
  649.                 m_ProgressIndicatorTimer = SetTimer(m_hwnd, 0, 500, (TIMERPROC)&UpdateProgressIndicator);
  650.  
  651.                 if (m_ProgressIndicatorTimer)
  652.                 {
  653.                     m_ProgressIndicator = 0;
  654.  
  655.                     m_LastProgressIndicator = 0;
  656.                     m_LastObjectCount = 0;
  657.  
  658.                     m_iProgressIndicatorImage = 0;
  659.                 
  660.                     m_flags |= HMM_FL_PROGRESS_INDICATOR;
  661.  
  662.                     fSuccess = TRUE;
  663.                 }
  664.             }
  665.         }
  666.  
  667.         if (!fSuccess)
  668.         {
  669.             rgPartRightEdges[0] = -1;
  670.             SendMessage(m_status, SB_SETPARTS, 1, (LPARAM)&rgPartRightEdges[0]);
  671.  
  672.             SendMessage(m_status, SB_SETTEXT, 0, (LPARAM)"");
  673.         }
  674.     }
  675.     Leave();
  676.  
  677.     return fSuccess;
  678. }
  679.  
  680.  
  681. VOID HeapMonitorManager::StopHeapDumpProgressIndicatorWorker ()
  682. {
  683.     if (m_flags & HMM_FL_PROGRESS_INDICATOR)
  684.     {
  685.         Enter();
  686.         {
  687.             KillTimer(m_hwnd, 0);
  688.             m_ProgressIndicatorTimer = 0;
  689.  
  690.             m_flags -= HMM_FL_PROGRESS_INDICATOR;
  691.  
  692.             INT rgPartRightEdges[1] = { -1 };
  693.             SendMessage(m_status, SB_SETPARTS, 1, (LPARAM)&rgPartRightEdges[0]);
  694.  
  695.             SendMessage(m_status, SB_SETTEXT, 0, (LPARAM)"");
  696.         }
  697.         Leave();
  698.     }
  699. }
  700.  
  701.  
  702. BOOL HeapMonitorManager::StartHeapDumpProgressIndicator ()
  703. {
  704.     ASSERT(CanSendUIMessages());
  705.     ASSERT(OnHeapDumpThread());
  706.  
  707.     return SendMessage(m_hwnd, HMM_WM_START_PROGRESS_INDICATOR, 0, 0) != FALSE;
  708. }
  709.  
  710.  
  711. VOID HeapMonitorManager::StopHeapDumpProgressIndicator ()
  712. {
  713.     ASSERT(CanSendUIMessages());
  714.     ASSERT(OnHeapDumpThread());
  715.  
  716.     SendMessage(m_hwnd, HMM_WM_STOP_PROGRESS_INDICATOR, 0, 0);
  717. }
  718.  
  719.  
  720. VOID HeapMonitorManager::SetStatusText (PCSTR text)
  721. {
  722.     ASSERT(CanSendUIMessages());
  723.  
  724.     if (m_flags & HMM_FL_PROGRESS_INDICATOR)
  725.     {
  726.         SendMessage(m_status, SB_SETTEXT, 1, (LPARAM)text);
  727.     }
  728.     else
  729.     {
  730.         SetWindowText(m_status, text);
  731.     }
  732. }
  733.  
  734.  
  735. BOOL HeapMonitorManager::AddTrayIcon ()
  736. {
  737.     ASSERT(!(m_flags & HMM_FL_ADDED_TRAY_ICON));
  738.  
  739.     BOOL ret;
  740.  
  741.     NOTIFYICONDATA nid;
  742.  
  743.     nid.cbSize = sizeof(nid);
  744.     ZeroMemory(&nid, sizeof(nid));
  745.     
  746.     nid.hWnd = m_hwnd;
  747.     nid.uFlags = (NIF_ICON | NIF_MESSAGE | NIF_TIP);
  748.     nid.uCallbackMessage = HMM_WM_ACTIVATE;
  749.     nid.hIcon = s_htrayicon;
  750.     CopyMemory(nid.szTip, "Java Heap Monitor", 18);
  751.  
  752.     ret = Shell_NotifyIcon(NIM_ADD, &nid);
  753.  
  754.     if (ret)
  755.     {
  756.         // Use critical section just to make flags modification atomic.
  757.         Enter();
  758.         {
  759.             ASSERT(!(m_flags & HMM_FL_ADDED_TRAY_ICON));
  760.             m_flags |= HMM_FL_ADDED_TRAY_ICON;
  761.         }
  762.         Leave();
  763.     }
  764.  
  765.     return ret;
  766. }
  767.  
  768.  
  769. BOOL HeapMonitorManager::RemoveTrayIconWorker ()
  770. {
  771.     NOTIFYICONDATA nid;
  772.  
  773.     nid.cbSize = sizeof(nid);
  774.     ZeroMemory(&nid, sizeof(nid));
  775.     
  776.     nid.hWnd = m_hwnd;
  777.  
  778.     return Shell_NotifyIcon(NIM_DELETE, &nid);
  779. }
  780.  
  781.  
  782. BOOL HeapMonitorManager::RemoveTrayIcon ()
  783. {
  784.     ASSERT(m_flags & HMM_FL_ADDED_TRAY_ICON);
  785.  
  786.     BOOL ret = RemoveTrayIconWorker();
  787.  
  788.     if (ret)
  789.     {
  790.         // Use critical section just to make flags modification atomic.
  791.         Enter();
  792.         {
  793.             ASSERT(m_flags & HMM_FL_ADDED_TRAY_ICON);
  794.             m_flags -= HMM_FL_ADDED_TRAY_ICON;
  795.         }
  796.         Leave();
  797.     }
  798.  
  799.     return ret;
  800. }
  801.  
  802.  
  803. VOID HeapMonitorManager::OnCreateWindow (HWND wnd, LPCREATESTRUCT pcs)
  804. {
  805.     BOOL result;
  806.  
  807.     m_hwnd = wnd;
  808.  
  809.     result = (m_status = CreateStatusWindow(
  810.         WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
  811.         "",
  812.         wnd,
  813.         IDC_STATUS)) != NULL;
  814.  
  815.     if (result)
  816.     {
  817.         // Minimum size of the progress indicator bitmaps.
  818.         SendMessage(m_status, SB_SETMINHEIGHT, 16, 0);
  819.  
  820.         CLIENTCREATESTRUCT ccs;  
  821.  
  822.         ccs.hWindowMenu = m_hmnuWindow; 
  823.         ccs.idFirstChild = IDM_WINDOW_FIRSTCHILD;
  824.  
  825.         result = (m_mdi = CreateWindow(
  826.                 "MDICLIENT",
  827.                 NULL, 
  828.                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL, 
  829.                 0, 0, 0, 0,
  830.                 wnd,
  831.                 NULL,
  832.                 m_hinst,
  833.                 &ccs)) != NULL;
  834.     }
  835.  
  836.     if (result)
  837.     {
  838.         ShowWindow(m_mdi, SW_SHOW);
  839.     }
  840. }
  841.  
  842.  
  843. VOID HeapMonitorManager::CreateNewHeapViewer ()
  844. {
  845.     HeapViewer *hv = new(HeapViewer());
  846.     if (hv)
  847.     {
  848.         hv->Initialize(this);
  849.         
  850.         hv->Release();
  851.     }
  852. }
  853.  
  854.  
  855. VOID HeapMonitorManager::CreateNewClassViewer ()
  856. {
  857.     ClassListViewer *clv = new(ClassListViewer());
  858.     if (clv)
  859.     {
  860.         clv->Initialize(this);
  861.         
  862.         clv->Release();
  863.     }
  864. }
  865.  
  866.  
  867. VOID HeapMonitorManager::CreateNewGCHistoryViewer ()
  868. {
  869.     GCHistoryViewer *gchv = new(GCHistoryViewer());
  870.     if (gchv)
  871.     {
  872.         gchv->Initialize(this);
  873.         
  874.         gchv->Release();
  875.     }
  876. }
  877.  
  878.  
  879. VOID HeapMonitorManager::CreateNewTrackedObjectListViewer ()
  880. {
  881.     ObjectListViewer *olv = new(ObjectListViewer());
  882.     if (olv)
  883.     {
  884.         olv->Initialize(this, "Tracked Objects", OID_FL_TRACKED);
  885.  
  886.         olv->Release();
  887.     }
  888. }
  889.  
  890.  
  891. VOID HeapMonitorManager::CreateNewTaggedObjectListViewer ()
  892. {
  893.     ObjectListViewer *olv = new(ObjectListViewer());
  894.     if (olv)
  895.     {
  896.         olv->Initialize(this, "Tagged Objects", OID_FL_TAGGED);
  897.  
  898.         olv->Release();
  899.     }
  900. }
  901.  
  902.  
  903. //static
  904. LRESULT CALLBACK HeapMonitorManager::WndProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
  905. {
  906.     HeapMonitorManager *hmm = (HeapMonitorManager*)GetWindowLong(wnd, GWL_USERDATA);
  907.     
  908.     switch (msg)
  909.     {
  910.     case WM_CREATE:
  911.         {
  912.             hmm = (HeapMonitorManager*)((CREATESTRUCT*)lParam)->lpCreateParams;
  913.  
  914.             SetWindowLong(wnd, GWL_USERDATA, (LONG)hmm);
  915.             hmm->AddRef();
  916.  
  917.             hmm->OnCreateWindow(wnd, (LPCREATESTRUCT)lParam);
  918.         }
  919.         return 0;
  920.  
  921.     case WM_COMMAND:
  922.         {
  923.             //WORD wNotifyCode = HIWORD(wParam); // notification code 
  924.             WORD wID = LOWORD(wParam);         // item, control, or accelerator identifier 
  925.             //HWND hwndCtl = (HWND) lParam;      // handle of control
  926.             switch (wID)
  927.             {
  928.             case IDM_STOPGO:
  929.                 hmm->StopOrGo();
  930.                 return 0;
  931.  
  932.             case IDM_WINDOW_NEWHEAPVIEWER:
  933.                 hmm->CreateNewHeapViewer();
  934.                 break;
  935.  
  936.             case IDM_WINDOW_NEWCLASSVIEWER:
  937.                 hmm->CreateNewClassViewer();
  938.                 break;
  939.  
  940.             case IDM_WINDOW_NEWGCSTATSVIEWER:
  941.                 hmm->CreateNewGCHistoryViewer();
  942.                 break;
  943.  
  944.             case IDM_WINDOW_NEWTRKOBJVIEWER:
  945.                 hmm->CreateNewTrackedObjectListViewer();
  946.                 break;
  947.  
  948.             case IDM_WINDOW_NEWTAGOBJVIEWER:
  949.                 hmm->CreateNewTaggedObjectListViewer();
  950.                 break;
  951.             }
  952.         }
  953.         break;
  954.  
  955.     case WM_CLOSE:
  956.  
  957.         BOOL fCanCloseNow;
  958.         fCanCloseNow = TRUE;
  959.     
  960.         hmm->Enter();
  961.         {
  962.             hmm->m_flags |= HMM_FL_CLOSED;
  963.  
  964.             hmm->GrayMenu(IDM_STOPGO);
  965.  
  966.             DWORD EventMask;
  967.             if (hmm->m_vminfo->GetEventMask(&EventMask) == S_OK)
  968.                 hmm->m_vminfo->SetEventMask(EventMask | JVM_MONITOR_GARBAGE_COLLECTIONS);
  969.  
  970.             if (hmm->m_flags & HMM_FL_STOPPED)
  971.             {
  972.                 fCanCloseNow = FALSE;
  973.  
  974.                 hmm->m_flags |= HMM_FL_GO;
  975.                 
  976.                 SetEvent(hmm->m_hresumeevt);
  977.             }
  978.         }
  979.         hmm->Leave();
  980.             
  981.         if (hmm->m_flags & HMM_FL_ADDED_TRAY_ICON)
  982.             hmm->RemoveTrayIcon();
  983.  
  984.         ShowWindow(wnd, SW_HIDE);
  985.  
  986.         hmm->SendClosingEvent();
  987.         
  988.         return 0;
  989.  
  990.     case HMM_WM_DESTROY_NOW:
  991.  
  992.         DestroyWindow(wnd);
  993.  
  994.         return 0;
  995.  
  996.     case WM_DESTROY:
  997.  
  998.         SetWindowLong(wnd, GWL_USERDATA, (LONG)NULL);
  999.         hmm->Release();
  1000.  
  1001.         break;
  1002.  
  1003.     case WM_SIZE:
  1004.         {
  1005.             LONG w = LOWORD(lParam);
  1006.             LONG h = HIWORD(lParam);
  1007.             
  1008.             RECT rc;
  1009.             GetClientRect(hmm->m_status, &rc);
  1010.             LONG statush = rc.bottom - rc.top;
  1011.             MoveWindow(hmm->m_status, 0, h-statush, w, h, TRUE);
  1012.             h -= statush;
  1013.  
  1014.             MoveWindow(hmm->m_mdi, 0, 0, w, h, TRUE);
  1015.         }
  1016.         return 0;
  1017.  
  1018.     case WM_SYSCOMMAND:
  1019.         if (wParam == SC_MINIMIZE)
  1020.         {
  1021.             ShowWindow(wnd, SW_MINIMIZE);
  1022.             ShowWindow(wnd, SW_HIDE);
  1023.             hmm->AddTrayIcon();
  1024.             return 0;
  1025.         }
  1026.         break;
  1027.  
  1028.     case HMM_WM_ACTIVATE:
  1029.         if (lParam == WM_LBUTTONUP)
  1030.         {
  1031.             hmm->RemoveTrayIcon();
  1032.             ShowWindow(wnd, SW_SHOW);
  1033.             ShowWindow(wnd, SW_RESTORE);
  1034.         }
  1035.         return 0;
  1036.  
  1037.     case HMM_WM_START_PROGRESS_INDICATOR:
  1038.         return hmm->StartHeapDumpProgressIndicatorWorker();
  1039.  
  1040.     case HMM_WM_STOP_PROGRESS_INDICATOR:
  1041.         hmm->StopHeapDumpProgressIndicatorWorker();
  1042.         return 0;
  1043.  
  1044.     case WM_DRAWITEM:
  1045.         DRAWITEMSTRUCT *pdis;
  1046.         pdis = (DRAWITEMSTRUCT*)lParam;
  1047.         if (ImageList_Draw(hmm->m_ProgressIndicatorImages, hmm->m_iProgressIndicatorImage, pdis->hDC, 0, 0, ILD_NORMAL))
  1048.             return 0;
  1049.         return 0;
  1050.  
  1051.     // REMIND: WM_COMMAND, WM_MENUCHAR, and WM_SETFOCUS need to be passed to
  1052.     // mdi proc
  1053.     }
  1054.  
  1055.     if (hmm)
  1056.     {
  1057.         HWND hmdi = hmm->m_mdi;
  1058.         if (hmdi)
  1059.             return DefFrameProc(wnd, hmdi, msg, wParam, lParam);
  1060.     }
  1061.     
  1062.     return DefWindowProc(wnd, msg, wParam, lParam);
  1063. }
  1064.  
  1065.  
  1066. //------------------------------------------------------------------------
  1067.  
  1068.  
  1069. PKGID HeapMonitorManager::LookupPackage (PKGID parentpkgid, PCWSTR pcszPackageName)
  1070. {
  1071.     PKGID pkgid = NULL;
  1072.  
  1073.     PkgTokenEntry *pkgent = GetPackageEntry(pcszPackageName);
  1074.     if (pkgent)
  1075.     {
  1076.         if (pkgent->id)
  1077.         {
  1078.             pkgid = pkgent->id;
  1079.         }
  1080.         else
  1081.         {
  1082.             pkgid = new(PackageIDWrapper());
  1083.             if (pkgid)
  1084.             {
  1085.                 pkgent->id = pkgid;
  1086.                 pkgid->vmid = (UniqueID)pkgent;
  1087.                 pkgid->parent = parentpkgid;
  1088.  
  1089.                 Leave();
  1090.                 {
  1091.                     SendPackageCreatedEvent(pkgid);
  1092.                 }
  1093.                 Enter();
  1094.             }
  1095.         }
  1096.     }
  1097.  
  1098.     return pkgid;
  1099. }
  1100.  
  1101.  
  1102. CLASSID HeapMonitorManager::LookupClass (ClassID vmid)
  1103. {
  1104.     CLASSID cls = (CLASSID)LookupID(vmid);
  1105.     if (!cls)
  1106.         cls = ClassLoaded(vmid);
  1107.  
  1108.     return cls;
  1109. }
  1110.  
  1111.  
  1112. OBJID HeapMonitorManager::LookupObject (ObjectID vmid)
  1113. {
  1114.     OBJID id;
  1115.     Enter();
  1116.     {
  1117.         id = (OBJID)LookupID(vmid);
  1118.         if (id == NULL)
  1119.             id = CreateOBJID(vmid);
  1120.     }
  1121.     Leave();
  1122.     return id;
  1123. }
  1124.  
  1125.  
  1126. THREADID HeapMonitorManager::LookupThread (ThreadID vmid)
  1127. {
  1128.     THREADID thd = (THREADID)LookupID(vmid);
  1129.     if (!thd)
  1130.         thd = ThreadCreated(vmid, TRUE);
  1131.     return thd;
  1132. }
  1133.  
  1134.  
  1135. int HeapMonitorManager::IterateIDs (IDITERFN *cb, PVOID cbtoken)
  1136. {
  1137.     // Not necessary, but no sense in entering the lock twice when the
  1138.     // caller can just use IterateIDs_Safe.
  1139.     ASSERT(!Entered());
  1140.  
  1141.     int ret;
  1142.  
  1143.     Enter();
  1144.     {
  1145.         ret = IterateIDs_Safe(cb, cbtoken);
  1146.     }
  1147.     Leave();
  1148.  
  1149.     return ret;
  1150. }
  1151.  
  1152.  
  1153. //static
  1154. int HeapMonitorManager::DeleteTransientIDs (PCVOID key, PVOID value, PVOID token)
  1155. {
  1156.     ID id = (ID)value;
  1157.     
  1158.     int result = 1;
  1159.  
  1160.     switch (id->type)
  1161.     {
  1162.     case ID_OBJECT:
  1163.         {
  1164.             OBJID obj = (OBJID)id;
  1165.             if (!(obj->flags & ALL_OID_NONTRANSIENT_FLAGS))
  1166.             {
  1167.                 delete(obj);
  1168.                 result = 0;
  1169.             }
  1170.             else
  1171.             {
  1172.                 obj->flags &= ~ALL_OID_TRANSIENT_FLAGS;
  1173.             }
  1174.         }
  1175.         break;
  1176.  
  1177.     case ID_STACKFRAME:
  1178.     case ID_ROOT:
  1179.     case ID_GHOST_THREAD:
  1180.         delete(id);
  1181.         result = 0;
  1182.         break;
  1183.  
  1184.     case ID_THREAD:
  1185.         THREADID thd = (THREADID)id;
  1186.         if (!(thd->flags & TID_FL_DEAD))
  1187.         {
  1188.             thd->curframe = NULL;
  1189.         }
  1190.         else
  1191.         {
  1192.             delete(thd);
  1193.             result = 0;
  1194.         }
  1195.         break;
  1196.     }
  1197.  
  1198.     return result;
  1199. }
  1200.  
  1201.  
  1202. //static
  1203. int HeapMonitorManager::ResetPerGCIDInfo (PCVOID key, PVOID val, PVOID token)
  1204. {
  1205.     ASSERT(((HeapMonitorManager*)token)->Entered());
  1206.  
  1207.     ID id = (ID)val;
  1208.  
  1209.     DWORD oldflags = id->flags;
  1210.     DWORD newflags = oldflags;
  1211.  
  1212.     newflags &= ~ALL_ID_PER_GC_FLAGS;
  1213.  
  1214.     switch (id->type)
  1215.     {
  1216.     case ID_CLASS:
  1217.         {
  1218.             CLASSID cls = (CLASSID)id;
  1219.             cls->liveinstances = 0;
  1220.             cls->livesize = 0;
  1221.             cls->agesum = 0;
  1222.             newflags &= ~ALL_CID_PER_GC_FLAGS;
  1223.         }
  1224.         break;
  1225.     }
  1226.  
  1227.     if (oldflags != newflags)
  1228.         id->flags = newflags;
  1229.  
  1230.     // REMIND: if you return 0, need to bump the change count
  1231.     return 1;
  1232. }
  1233.  
  1234.  
  1235. HeapMonitorManager::PkgTokenEntry *HeapMonitorManager::GetPackageEntry (PCWSTR pkgname)
  1236. {
  1237.     ASSERT(Entered());
  1238.  
  1239.     PkgTokenEntry *ent = NULL;
  1240.     int namelen = wcslen(pkgname);
  1241.     int namesize = (namelen+1)*sizeof(*pkgname);
  1242.  
  1243.     // TODO: hash using pooled strings?
  1244.  
  1245.     if (m_pkgents != NULL)
  1246.     {
  1247.         ent = &m_pkgents[0];
  1248.     
  1249.         for (;;)
  1250.         {
  1251.             if (ent->name == NULL)
  1252.                 break;
  1253.  
  1254.             if (memcmp(pkgname, ent->name, namesize) == 0)
  1255.                 break;
  1256.  
  1257.             ent++;
  1258.             if (ent == m_pkgents+m_npkgents)
  1259.             {
  1260.                 DWORD newcount = m_npkgents*2;
  1261.                 PkgTokenEntry *newpkgents = new(PkgTokenEntry[newcount]);
  1262.                 if (newpkgents != NULL)
  1263.                 {
  1264.                     CopyMemory(newpkgents, m_pkgents, m_npkgents*sizeof(*m_pkgents));
  1265.                     ZeroMemory(newpkgents+m_npkgents, m_npkgents*sizeof(*m_pkgents));
  1266.                     m_pkgents = newpkgents;
  1267.                     ent = newpkgents+m_npkgents;
  1268.                     m_npkgents = newcount;
  1269.                 }
  1270.                 else
  1271.                 {
  1272.                     ent = NULL;
  1273.                 }
  1274.  
  1275.                 break;
  1276.             }
  1277.         }
  1278.     }
  1279.     else
  1280.     {
  1281.         m_npkgents = 10;
  1282.         m_pkgents = new(PkgTokenEntry[m_npkgents]);
  1283.         if (m_pkgents != NULL)
  1284.         {
  1285.             ZeroMemory(m_pkgents, m_npkgents*sizeof(*m_pkgents));
  1286.             ent = &m_pkgents[0];
  1287.         }
  1288.         else
  1289.         {
  1290.             ent = NULL;
  1291.         }
  1292.     }
  1293.  
  1294.     if (ent != NULL && ent->name == NULL)
  1295.     {
  1296.         if ((ent->name = new(WCHAR[namelen+1])) != NULL)
  1297.             CopyMemory(ent->name, pkgname, namesize);
  1298.         else
  1299.             ent = NULL;
  1300.     }
  1301.  
  1302.     return ent;
  1303. }
  1304.  
  1305.  
  1306. BOOL HeapMonitorManager::FetchClassInfo (CLASSID id)
  1307. {
  1308.     ASSERT(Entered());
  1309.  
  1310.     FieldID *pfields;
  1311.     unsigned nfields;
  1312.     HRESULT hr = m_vminfo->GetClassFields((ClassID)id->vmid, &nfields, &pfields);
  1313.     if (EVAL(hr == S_OK))
  1314.     {
  1315.         size_t szfldinfo = FIELD_OFFSET(FieldInfoHeader, fldinfo) + sizeof(FieldInfo) * nfields;
  1316.  
  1317.         FieldInfoHeader *hdr = (FieldInfoHeader*)new(BYTE[szfldinfo]);
  1318.         if (hdr != NULL)
  1319.         {
  1320.             FieldInfo *flds = &hdr->fldinfo[0];
  1321.             
  1322.             unsigned nrefs = 0;
  1323.         
  1324.             for (unsigned i = 0; i < nfields; i++)
  1325.             {
  1326.                 flds[i].id = pfields[i];
  1327.  
  1328.                 hr = m_vminfo->FieldInformation(pfields[i], &flds[i].name, &flds[i].flags);
  1329.                 if (hr != S_OK)
  1330.                     break;
  1331.  
  1332.                 if (   (flds[i].flags & JVM_FIELD_OBJECTREF)
  1333.                     && !(flds[i].flags & JVM_FIELD_STATIC))
  1334.                 {
  1335.                     nrefs++;
  1336.                 }
  1337.             }
  1338.  
  1339.             hdr->nfields = i;
  1340.             hdr->nreffields = nrefs;
  1341.  
  1342.             id->flds = hdr;
  1343.  
  1344.             unsigned nspecialclsids;
  1345.             ClassID *pspecialclsids;
  1346.             DWORD *pclsflags;
  1347.             if (m_vminfo->GetSpecialClassProperties(&nspecialclsids, &pspecialclsids, &pclsflags) == S_OK)
  1348.             {
  1349.                 for (unsigned i = 0; i < nspecialclsids; i++)
  1350.                 {
  1351.                     if (pspecialclsids[i] == id->vmid)
  1352.                     {
  1353.                         DWORD flags = pclsflags[i];
  1354.  
  1355.                         if (flags & JVM_CLS_HAS_DESCRIPTION)
  1356.                             id->flags |= CID_FL_HAS_DESCRIPTION;
  1357.  
  1358.                         break;
  1359.                     }
  1360.                 }
  1361.  
  1362.                 CoTaskMemFree(pspecialclsids);
  1363.                 CoTaskMemFree(pclsflags);
  1364.             }
  1365.         }
  1366.         else
  1367.         {
  1368.             hr = E_OUTOFMEMORY;
  1369.         }
  1370.     }
  1371.  
  1372.     return SUCCEEDED(hr);
  1373. }
  1374.  
  1375.  
  1376. //static
  1377. int HeapMonitorManager::FetchClassInfoCB (ID id, PVOID cbtoken)
  1378. {
  1379.     HeapMonitorManager *hmm = (HeapMonitorManager*)cbtoken;
  1380.  
  1381.     if (id->type == ID_CLASS)
  1382.     {
  1383.         CLASSID clsid = (CLASSID)id;
  1384.         if (clsid->flds == NULL)
  1385.         {
  1386.             hmm->FetchClassInfo(clsid);
  1387.         }
  1388.     }
  1389.  
  1390.     return 1;
  1391. }
  1392.  
  1393.  
  1394. PCSTR HeapMonitorManager::FetchContainerName (PSTR **prgpszDescr, CONTAINER_TYPE type, BOOL fVerbose)
  1395. {
  1396.     PSTR pszDescr = NULL;
  1397.  
  1398.     Enter();
  1399.     {
  1400.         PSTR *rgpszDescr = *prgpszDescr;
  1401.         if (rgpszDescr == NULL)
  1402.         {
  1403.             rgpszDescr = new(PSTR[C_LAST - C_FIRST - 1]);
  1404.             if (rgpszDescr != NULL)
  1405.             {
  1406.                 ZeroMemory(rgpszDescr, sizeof(PSTR)*(C_LAST - C_FIRST - 1));
  1407.                 *prgpszDescr = rgpszDescr;
  1408.             }
  1409.         }
  1410.  
  1411.         if (rgpszDescr != NULL)
  1412.         {
  1413.             int iDescr = type - C_FIRST - 1;
  1414.             pszDescr = rgpszDescr[iDescr];
  1415.             if (pszDescr == NULL)
  1416.             {
  1417.                 PWSTR pdescr;
  1418.                 PWSTR *ppdescr1;
  1419.                 PWSTR *ppdescr2;
  1420.                 if (fVerbose)
  1421.                 {
  1422.                     ppdescr1 = NULL;
  1423.                     ppdescr2 = &pdescr;
  1424.                 }
  1425.                 else
  1426.                 {
  1427.                     ppdescr1 = &pdescr;
  1428.                     ppdescr2 = NULL;
  1429.                 }
  1430.                 
  1431.                 if (m_vmheapmon->GetContainerDescription((CONTAINER_TYPE)type, ppdescr1, ppdescr2) == S_OK)
  1432.                 {
  1433.                     UnicodeToANSI(pdescr, -1, &pszDescr);
  1434.                     rgpszDescr[iDescr] = pszDescr;
  1435.                 }
  1436.             }
  1437.         }
  1438.     }
  1439.     Leave();
  1440.  
  1441.     if (pszDescr == NULL)
  1442.         pszDescr = "???";
  1443.  
  1444.     return pszDescr;
  1445. }
  1446.  
  1447.  
  1448. //------------------------------------------------------------------------
  1449.  
  1450.  
  1451. HeapMonitorManager::ExpandObjectResults HeapMonitorManager::ExpandObject (
  1452.         ObjectID vmid, OBJID *pid,
  1453.         ExpandObjectAddObjectIDReferenceProc *vmidcb,
  1454.         ExpandObjectAddOBJIDReferenceProc *idcb,
  1455.         PVOID token)
  1456. {
  1457.     OBJID id = *pid;
  1458.  
  1459.     if (id)
  1460.     {
  1461.         if (id->flags & (OID_FL_NO_REFERENCES | OID_FL_DEAD))
  1462.             return EOR_NO_REFERENCES;
  1463.             
  1464.         vmid = id->GetObjectID();
  1465.     }
  1466.  
  1467.     BOOL fExpanding;
  1468.  
  1469.     Enter();
  1470.     {
  1471.         if (!(m_flags & HMM_FL_HEAP_EXPLORED))
  1472.         {
  1473.             if (!id)
  1474.             {
  1475.                 // Heap enumeration has not completed, so we must hash all
  1476.                 // objects discovered here to detect cycles.
  1477.  
  1478.                 id = (OBJID)LookupObject(vmid);
  1479.                 if (!id)
  1480.                 {
  1481.                     Leave();
  1482.                     return EOR_FAILED;
  1483.                 }
  1484.  
  1485.                 *pid = id;
  1486.             }
  1487.  
  1488.             fExpanding = !(id->flags & OID_FL_EXPANDED);
  1489.             if (fExpanding)
  1490.                 id->flags |= OID_FL_EXPANDED;
  1491.         }
  1492.         else
  1493.         {
  1494.             // The heap has been completely explored, so only "special"
  1495.             // objects need to be hashed.
  1496.  
  1497.             if (!id)
  1498.                 id = (OBJID)LookupID(vmid);
  1499.             fExpanding = FALSE;
  1500.         }
  1501.     }
  1502.     Leave();
  1503.  
  1504.     if (!id)
  1505.         ASSERT(!fExpanding);
  1506.  
  1507.     ExpandObjectResults result = EOR_FAILED;
  1508.  
  1509.     if (!id || !(id->flags & (OID_FL_NULL_REFERENCES | OID_FL_NO_REFERENCES)))
  1510.     {
  1511.         ClassID clsid;
  1512.         if (m_vminfo->ObjectInformation(vmid, &clsid) == S_OK)
  1513.         {
  1514.             CLASSID cls = LookupClass(clsid);
  1515.             if (cls)
  1516.             {
  1517.                 result = EOR_EXPANDED;
  1518.  
  1519.                 ULONG nflds = 0;
  1520.                 FieldInfoHeader *flds = NULL;
  1521.  
  1522.                 if (cls->flags & CID_FL_ARRAY)
  1523.                 {
  1524.                     if (cls->flags & CID_FL_ARRAY_OF_OBJECTS)
  1525.                     {
  1526.                         nflds = ULONG_MAX;
  1527.                     }
  1528.                 }
  1529.                 else
  1530.                 {
  1531.                     flds = cls->flds;
  1532.                     if (flds && flds->nreffields != 0)
  1533.                     {
  1534.                         nflds = flds->nfields;
  1535.                     }
  1536.                 }
  1537.  
  1538.                 if (nflds != 0)
  1539.                 {
  1540.                     BOOL fFoundRef = FALSE;
  1541.                 
  1542.                     for (unsigned i = 0; i < nflds; i++)
  1543.                     {
  1544.                         // NOTE: The following will not work on VMs older than
  1545.                         // build 3223.  See the comment at the top of this
  1546.                         // file.
  1547.  
  1548.                         __int64 value;
  1549.                         if (!flds)
  1550.                         {
  1551.                             if (m_vminfo->GetArrayElement(vmid, i, &value) != S_OK)
  1552.                                 break;
  1553.                         }
  1554.                         else
  1555.                         {
  1556.                             FieldInfo *pfld = &flds->fldinfo[i];
  1557.                             if (   !(pfld->flags & JVM_FIELD_OBJECTREF)
  1558.                                 || (pfld->flags & JVM_FIELD_STATIC))
  1559.                             {
  1560.                                 continue;
  1561.                             }
  1562.  
  1563.                             // This may validly fail for fields in variable-size objects.
  1564.                             if (m_vminfo->GetObjectField(vmid, pfld->id, &value) != S_OK)
  1565.                             {
  1566.                                 // TODO: for non-variable-size classes, set HMM_FL_INACCURATE
  1567.                                 continue;
  1568.                             }
  1569.                         }
  1570.  
  1571.                         ObjectID refvmid = (ObjectID)value;
  1572.                         if (refvmid)
  1573.                         {
  1574.                             fFoundRef = TRUE;
  1575.  
  1576.                             OBJID refid = NULL;
  1577.                             if (fExpanding)
  1578.                             {
  1579.                                 refid = DiscoveredObject(refvmid);
  1580.                                 if (!refid)
  1581.                                     continue;
  1582.                             }
  1583.                             else
  1584.                             {
  1585.                                 refid = (OBJID)LookupID(refvmid);
  1586.                             }
  1587.                             if (refid)
  1588.                                 (*idcb)(refid, token);
  1589.                             else
  1590.                                 (*vmidcb)(refvmid, token);
  1591.                         }
  1592.                     }
  1593.  
  1594.                     if (!fFoundRef)
  1595.                         goto no_refs;
  1596.                 }
  1597.                 else
  1598.                 {
  1599.             no_refs:
  1600.                 
  1601.                     Enter();
  1602.                     {
  1603.                         if (!id)
  1604.                             id = (OBJID)LookupID(vmid);
  1605.                         if (id)
  1606.                         {
  1607.                             id->flags |= OID_FL_NO_REFERENCES;
  1608.                             *pid = id;
  1609.                         }
  1610.                     }
  1611.                     Leave();
  1612.  
  1613.                     result = EOR_NO_REFERENCES;
  1614.                 }
  1615.             }
  1616.         }
  1617.     }
  1618.  
  1619.     return result;
  1620. }
  1621.  
  1622.  
  1623. BOOL HeapMonitorManager::FindObjectReferences (ObjectID vmid, SearchProc *cb, PVOID token)
  1624. {
  1625.     ASSERT(vmid != NULL);
  1626.  
  1627.     SearchOperation findrefsop;
  1628.     findrefsop.op = SOP_REFERENCE_TO;
  1629.     findrefsop.refersto.oid = vmid;
  1630.     findrefsop.proc = cb;
  1631.     findrefsop.token = token;
  1632.  
  1633.     return RegisterSearchOperation(&findrefsop);
  1634. }
  1635.  
  1636.  
  1637. BOOL HeapMonitorManager::FindClassInstances (CLASSID cls, SearchProc *cb, PVOID token)
  1638. {
  1639.     SearchOperation findinst;
  1640.     findinst.op = SOP_INSTANCE_OF;
  1641.     findinst.instanceof.cid = cls->vmid;
  1642.     findinst.proc = cb;
  1643.     findinst.token = token;
  1644.  
  1645.     return RegisterSearchOperation(&findinst);
  1646. }
  1647.  
  1648.  
  1649. OBJID HeapMonitorManager::CreateOBJID (ObjectID vmid)
  1650. {
  1651.     ASSERT(Entered());
  1652.     ASSERT(!IsExecutionSuspended_Safe());
  1653.     ASSERT(!LookupID(vmid));
  1654.  
  1655.     OBJID id = new(ObjectIDWrapper());
  1656.     if (id)
  1657.     {
  1658.         id->vmid = vmid;
  1659.         id->flags = 0;
  1660.  
  1661.         if (!AddID(vmid, id))
  1662.         {
  1663.             delete(id);
  1664.             id = NULL;
  1665.  
  1666.             m_flags |= HMM_FL_INACCURATE;
  1667.         }
  1668.     }
  1669.     return id;
  1670. }
  1671.  
  1672.  
  1673. OBJID HeapMonitorManager::DiscoveredObject (ObjectID vmid)
  1674. {
  1675.     OBJID id;
  1676.  
  1677.     BOOL fStatusChanged = FALSE;
  1678.  
  1679.     Enter();
  1680.     {
  1681.         id = (OBJID)LookupID(vmid);
  1682.         if (id)
  1683.         {
  1684.             if (id->flags & ID_FL_DISCOVERED)
  1685.             {
  1686.                 if (!(id->flags & OID_FL_MULTIPLE_REFERENCES))
  1687.                 {
  1688.                     m_gcinfo.nObjectsWithMultipleReferences++;
  1689.                     id->flags |= OID_FL_MULTIPLE_REFERENCES;
  1690.                     fStatusChanged = TRUE;
  1691.                 }
  1692.             }
  1693.             else
  1694.             {
  1695.                 id->flags |= ID_FL_DISCOVERED;
  1696.             }
  1697.         }
  1698.         else
  1699.         {
  1700.             id = CreateOBJID(vmid);
  1701.             if (id)
  1702.                 id->flags |= ID_FL_DISCOVERED;
  1703.         }
  1704.     }
  1705.     Leave();
  1706.  
  1707.     if (fStatusChanged)
  1708.     {
  1709.         ASSERT(id);
  1710.         SendObjectStatusChanged(id);
  1711.     }
  1712.  
  1713.     return id;
  1714. }
  1715.  
  1716.  
  1717. ID HeapMonitorManager::DiscoveredRoot (CONTAINER_TYPE type, UniqueID vmid, UniqueID extraid)
  1718. {
  1719.     ID id = LookupID(vmid);
  1720.     if (!id)
  1721.     {
  1722.         switch (type)
  1723.         {
  1724.         case C_RT_CLASS:
  1725.             id = ClassLoaded(vmid);
  1726.             break;
  1727.  
  1728.         case C_RT_THREAD:
  1729.             id = ThreadCreated(vmid, TRUE);
  1730.             break;
  1731.  
  1732.         case C_RT_JIT:
  1733.         case C_RT_NATIVE:
  1734.         case C_RT_NATIVEGC:
  1735.         case C_RT_COM:
  1736.         case C_RT_INTERPRETED:
  1737.         case C_RT_FASTINTERPRETED:
  1738.         case C_RT_INTERNALFRAME:
  1739.             {
  1740.                 ASSERT(m_lastthreadid);
  1741.                 ASSERT(LookupID(m_lastthreadid->vmid) == m_lastthreadid);
  1742.             
  1743.                 STACKID stkid = new(StackIDWrapper());
  1744.                 if (stkid)
  1745.                 {
  1746.                     // Roots can only be discovered through heap dumping, the
  1747.                     // only caller of this method - so we're only serializing
  1748.                     // the one writer with multiple readers.
  1749.                     Enter();
  1750.                     {
  1751.                         if (AddID(vmid, stkid))
  1752.                         {
  1753.                             stkid->vmid = vmid;
  1754.                             stkid->frmtype = type;
  1755.                             
  1756.                             MethodID methodid = NULL;
  1757.                             if (   type == C_RT_JIT
  1758.                                 || type == C_RT_NATIVE
  1759.                                 || type == C_RT_COM
  1760.                                 || type == C_RT_INTERPRETED
  1761.                                 || type == C_RT_FASTINTERPRETED)
  1762.                             {
  1763.                                 methodid = extraid;
  1764.                             }
  1765.                             stkid->methodid = methodid;
  1766.  
  1767.                             stkid->thd = m_lastthreadid;
  1768.  
  1769.                             // StackIDs may be reported multiple times and in any order.
  1770.  
  1771.                             STACKID *pparent = &stkid->thd->curframe;
  1772.                             while (*pparent && stkid->vmid >= (*pparent)->vmid)
  1773.                                 pparent = &(*pparent)->parent;
  1774.                             stkid->parent = *pparent;
  1775.                             *pparent = stkid;
  1776.  
  1777.                             id = stkid;
  1778.                         }
  1779.                         else
  1780.                         {
  1781.                             delete(stkid);
  1782.                         }
  1783.                     }
  1784.                     Leave();
  1785.                 }
  1786.             }
  1787.             break;
  1788.  
  1789.         default:
  1790.             Enter();
  1791.             {
  1792.                 id = LookupID(vmid);
  1793.                 if (!id)
  1794.                 {
  1795.                     ROOTID rootid = new(RootIDWrapper());
  1796.                     if (rootid)
  1797.                     {
  1798.                         rootid->vmid = vmid;
  1799.                     
  1800.                         rootid->roottype = type;
  1801.                         rootid->rootid1 = vmid;
  1802.                         rootid->rootid2 = extraid;
  1803.  
  1804.                         if (AddID(vmid, rootid))
  1805.                             id = rootid;
  1806.                         else
  1807.                             delete(rootid);
  1808.                     }
  1809.                 }
  1810.             }
  1811.             Leave();
  1812.  
  1813.             break;
  1814.         }
  1815.     }
  1816.  
  1817.     if (id)
  1818.     {
  1819.         if (!(id->flags & ID_FL_DISCOVERED))
  1820.         {
  1821.             m_gcinfo.rgcRoots[type - C_FIRST - 1]++;
  1822.  
  1823.             // Currently flags of all root IDs are manipulated only on the
  1824.             // event thread.
  1825.             id->flags |= ID_FL_DISCOVERED;
  1826.         }
  1827.     }
  1828.  
  1829.     return id;
  1830. }
  1831.  
  1832.  
  1833. BOOL HeapMonitorManager::RegisterSearchOperation (SearchOperation *searchitem)
  1834. {
  1835.     BOOL result = FALSE;
  1836.  
  1837.     SearchHeapInfoCallback *hicb = m_searchcb;
  1838.     if (!hicb)
  1839.         hicb = new(SearchHeapInfoCallback(this));
  1840.  
  1841.     if (hicb)
  1842.     {
  1843.         Enter();
  1844.         {
  1845.             if (m_searchcb == hicb)
  1846.             {
  1847.                 ;
  1848.             }
  1849.             else
  1850.             {
  1851.                 if (!m_searchcb)
  1852.                 {
  1853.                     m_searchcb = hicb;
  1854.                 }
  1855.                 else
  1856.                 {
  1857.                     hicb->Release();
  1858.                     hicb = m_searchcb;
  1859.                 }
  1860.             }
  1861.  
  1862.             SearchOperation *newworkitem = new(SearchOperation());
  1863.             if (newworkitem)
  1864.             {
  1865.                 *newworkitem = *searchitem;
  1866.  
  1867.                 hicb->AddSearchOperation(newworkitem);
  1868.  
  1869.                 result = RegisterHeapWalk(hicb, JVM_WALKHEAP_NO_ROOTS);
  1870.             }
  1871.         }
  1872.         Leave();
  1873.     }
  1874.  
  1875.     return result;
  1876. }
  1877.  
  1878.  
  1879. BOOL HeapMonitorManager::RegisterHeapWalk (IWalkHeapCallback *cb, DWORD HeapWalkFlags)
  1880. {
  1881.     BOOL result = TRUE;
  1882.  
  1883.     if (!m_vmheapmon2)
  1884.     {
  1885.         result = FALSE;
  1886.     }
  1887.     else
  1888.     {
  1889.         Enter();
  1890.         {
  1891.             BOOL fQueueSearch = FALSE;
  1892.             BOOL fScanHeapNow = FALSE;
  1893.         
  1894.             if (GetCurrentThreadId() == m_tid)
  1895.             {
  1896.                 // Called on the gui thread.  Check if execution is about to resume.
  1897.                 // If not, queue a request to search and wake up the heap thread.
  1898.  
  1899.                 if (!IsExecutionSuspended_Safe())
  1900.                 {
  1901.                     fQueueSearch = TRUE;
  1902.                 }
  1903.                 else
  1904.                 {
  1905.                     result = FALSE;
  1906.                 }
  1907.             }
  1908.             else
  1909.             {
  1910.                 // Called from the heap thread.  If the END container has been
  1911.                 // received, we can initiate the search directly.  If not, queue a
  1912.                 // request to search when END is received.
  1913.  
  1914.                 fQueueSearch = TRUE;
  1915.  
  1916.                 if (m_flags & HMM_FL_HEAP_EXPLORED)
  1917.                 {
  1918.                     fScanHeapNow = TRUE;
  1919.                 }
  1920.             }
  1921.  
  1922.             if (fQueueSearch)
  1923.             {
  1924.                 // Tack this request onto the search list.  When the heap thread
  1925.                 // is ready, it will remove the entire list and search for all of
  1926.                 // the objects at once in a single heap dump.
  1927.  
  1928.                 PendingHeapWalk *workitem = new(PendingHeapWalk());
  1929.                 result = (workitem != NULL);
  1930.                 if (result)
  1931.                 {
  1932.                     (workitem->cb = cb)->AddRef();
  1933.                     workitem->HeapWalkFlags = HeapWalkFlags;
  1934.  
  1935.                     workitem->next = m_heapwalks;
  1936.                     m_heapwalks = workitem;
  1937.                 }
  1938.             }
  1939.  
  1940.             if (result)
  1941.             {
  1942.                 if (fScanHeapNow)
  1943.                 {
  1944.                     Leave();
  1945.  
  1946.                     StartHeapDumpProgressIndicator();
  1947.  
  1948.                     SetStatusText("Searching...");
  1949.  
  1950.                     m_vmheapmon2->WalkHeap(cb, HeapWalkFlags);
  1951.  
  1952.                     StopHeapDumpProgressIndicator();
  1953.  
  1954.                     SetStatusText("Search complete.");
  1955.  
  1956.                     return TRUE;
  1957.                 }
  1958.                 else
  1959.                 {
  1960.                     SetEvent(m_hresumeevt);
  1961.                 }
  1962.             }
  1963.         }
  1964.         Leave();
  1965.     }
  1966.  
  1967.     return result;
  1968. }
  1969.  
  1970.  
  1971. //------------------------------------------------------------------------
  1972.  
  1973.  
  1974. BOOL HeapMonitorManager::ToggleObjectTracking (OBJID obj, ObjectID vmid)
  1975. {
  1976.     ASSERT(obj != NULL || vmid != NULL);
  1977.     if (vmid == NULL)
  1978.         ASSERT(obj->flags & OID_FL_DEAD);
  1979.  
  1980.     BOOL result;
  1981.  
  1982.     Enter();
  1983.     {
  1984.         if (obj == NULL)
  1985.             obj = LookupObject(vmid);
  1986.         result = (obj != NULL);
  1987.         if (result)
  1988.         {
  1989.             if (!(obj->flags & OID_FL_TRACKED))
  1990.             {
  1991.                 TrackedObjectList *trkent = *FindTrackedObjectEntry(obj);
  1992.                 if (obj->flags & ALL_OID_NONTRANSIENT_FLAGS)
  1993.                     ASSERT(trkent != NULL);
  1994.                 
  1995.                 if (trkent != NULL)
  1996.                 {
  1997.                     ASSERT(trkent->vmhid != NULL);
  1998.                     obj->flags |= OID_FL_TRACKED;
  1999.                 }
  2000.                 else
  2001.                 {
  2002.                     trkent = CreateTrackedObjectEntry(obj);
  2003.  
  2004.                     if (trkent != NULL)
  2005.                     {
  2006.                         obj->flags |= OID_FL_TRACKED;
  2007.                     }
  2008.                     else
  2009.                     {
  2010.                         result = FALSE;
  2011.                     }
  2012.                 }
  2013.             }
  2014.             else
  2015.             {
  2016.                 TrackedObjectList **ptrkent = FindTrackedObjectEntry(obj);
  2017.                 ASSERT(*ptrkent != NULL);
  2018.  
  2019.                 obj->flags -= OID_FL_TRACKED;
  2020.  
  2021.                 if (!(obj->flags & ALL_OID_NONTRANSIENT_FLAGS))
  2022.                 {
  2023.                     DestroyTrackedObjectEntry(ptrkent);
  2024.                 }
  2025.             }
  2026.         }
  2027.     }
  2028.     Leave();
  2029.  
  2030.     if (result)
  2031.         SendObjectStatusChanged(obj);
  2032.     
  2033.     return result;
  2034. }
  2035.  
  2036.  
  2037. BOOL HeapMonitorManager::SetObjectTag (OBJID obj, PCSTR newtag)
  2038. {
  2039.     ASSERT(obj != NULL);
  2040.  
  2041.     BOOL result = TRUE;
  2042.     BOOL update = TRUE;
  2043.  
  2044.     if (newtag != NULL || (obj->flags & OID_FL_TAGGED))
  2045.     {
  2046.         PSTR newtagmem = NULL;
  2047.         if (newtag != NULL)
  2048.         {
  2049.             int len = strlen(newtag);
  2050.             newtagmem = new(CHAR[len+1]);
  2051.             if (newtagmem != NULL)
  2052.                 CopyMemory(newtagmem, newtag, len+1);
  2053.             else
  2054.                 result = FALSE;
  2055.         }
  2056.  
  2057.         if (result)
  2058.         {
  2059.             Enter();
  2060.             {
  2061.                 TrackedObjectList **ptrkent = FindTrackedObjectEntry(obj);
  2062.                 TrackedObjectList *trkent = *ptrkent;
  2063.                 if (obj->flags & ALL_OID_NONTRANSIENT_FLAGS)
  2064.                     ASSERT(trkent != NULL);
  2065.  
  2066.                 if (trkent == NULL)
  2067.                 {
  2068.                     trkent = CreateTrackedObjectEntry(obj);
  2069.                     if (trkent == NULL)
  2070.                     {
  2071.                         result = FALSE;
  2072.                         update = FALSE;
  2073.                         delete(newtagmem);
  2074.                     }
  2075.                 }
  2076.  
  2077.                 if (trkent != NULL)
  2078.                 {
  2079.                     if (trkent->tag != NULL)
  2080.                         delete(trkent->tag);
  2081.  
  2082.                     if (newtagmem == NULL)
  2083.                     {
  2084.                         ASSERT(trkent->tag != NULL);
  2085.                         ASSERT(obj->flags & OID_FL_TAGGED);
  2086.  
  2087.                         trkent->tag = NULL;
  2088.                         obj->flags -= OID_FL_TAGGED;
  2089.                         update = TRUE;
  2090.  
  2091.                         if (!(obj->flags & ALL_OID_NONTRANSIENT_FLAGS))
  2092.                             DestroyTrackedObjectEntry(ptrkent);
  2093.                     }
  2094.                     else
  2095.                     {
  2096.                         trkent->tag = newtagmem;
  2097.                         obj->flags |= OID_FL_TAGGED;
  2098.                     }
  2099.                 }
  2100.             }
  2101.             Leave();
  2102.  
  2103.             if (update)
  2104.                 SendObjectStatusChanged(obj);
  2105.         }
  2106.     }
  2107.     
  2108.     return result;
  2109. }
  2110.  
  2111.  
  2112. PCSTR HeapMonitorManager::GetObjectTag (OBJID obj)
  2113. {
  2114.     // Use of return value must be externally synchronized
  2115.     ASSERT(Entered());
  2116.  
  2117.     PCSTR tag;
  2118.  
  2119.     if (obj->flags & OID_FL_TAGGED)
  2120.     {
  2121.         TrackedObjectList *trkent = *FindTrackedObjectEntry(obj);
  2122.         ASSERT(trkent != NULL);
  2123.         tag = trkent->tag;
  2124.     }
  2125.     else
  2126.     {
  2127.         tag = NULL;
  2128.     }
  2129.  
  2130.     return tag;
  2131. }
  2132.  
  2133.  
  2134. int HeapMonitorManager::IterateSpecialObjects (SPECIALOBJITERFN *cb, PVOID token)
  2135. {
  2136.     int result = 1;
  2137.  
  2138.     for (TrackedObjectList *trkent = m_trackedobjs; trkent != NULL; )
  2139.     {
  2140.         TrackedObjectList *next = trkent->next;
  2141.         result = (*cb)(trkent->obj, token);
  2142.         if (result <= 0)
  2143.             break;
  2144.         trkent = next;
  2145.     }
  2146.  
  2147.     return result;
  2148. }
  2149.  
  2150.  
  2151. HeapMonitorManager::TrackedObjectList **HeapMonitorManager::FindTrackedObjectEntry (OBJID obj)
  2152. {
  2153.     TrackedObjectList **ptrkent = &m_trackedobjs;
  2154.     for (;;)
  2155.     {
  2156.         TrackedObjectList *trkent = *ptrkent;
  2157.         if (trkent == NULL || trkent->obj == obj)
  2158.             break;
  2159.         ptrkent = &trkent->next;
  2160.     }
  2161.     return ptrkent;
  2162. }
  2163.  
  2164.  
  2165. HeapMonitorManager::TrackedObjectList *HeapMonitorManager::CreateTrackedObjectEntry (OBJID obj)
  2166. {
  2167.     ASSERT(Entered());
  2168.     ASSERT(!(obj->flags & OID_FL_DEAD));
  2169.  
  2170.     TrackedObjectList *trkent = new(TrackedObjectList());
  2171.     if (trkent != NULL)
  2172.     {
  2173.         ZeroMemory(trkent, sizeof(*trkent));
  2174.     
  2175.         if (m_vminfo->GetHandlesToObjects(1, &obj->vmid, &trkent->vmhid) == S_OK)
  2176.         {
  2177.             trkent->obj = obj;
  2178.             EVAL(m_vminfo->ObjectInformation(obj->vmid, &trkent->vmclsid) == S_OK);
  2179.  
  2180.             trkent->next = m_trackedobjs;
  2181.             m_trackedobjs = trkent;
  2182.         }
  2183.         else
  2184.         {
  2185.             delete(trkent);
  2186.             trkent = NULL;
  2187.         }
  2188.     }
  2189.  
  2190.     return trkent;
  2191. }
  2192.  
  2193.  
  2194. VOID HeapMonitorManager::DestroyTrackedObjectEntry (TrackedObjectList **ptrkent)
  2195. {
  2196.     if ((*ptrkent)->vmhid != NULL)
  2197.         EVAL(m_vminfo->FreeHandlesToObjects(1, &(*ptrkent)->vmhid) == S_OK);
  2198.  
  2199.     TrackedObjectList *trash = *ptrkent;
  2200.     *ptrkent = trash->next;
  2201.     delete(trash);
  2202. }
  2203.  
  2204.  
  2205. //------------------------------------------------------------------------
  2206.  
  2207.  
  2208. //static
  2209. VOID HeapMonitorManager::StoppedExecutionCB (IHeapMonitorClient *client, PVOID token)
  2210. {
  2211.     client->OnStoppedExecution();
  2212. }
  2213.  
  2214.  
  2215. VOID HeapMonitorManager::SendSuspendedEvent ()
  2216. {
  2217.     IterateClients(HMC_UNMASKABLE_EVENTS, &StoppedExecutionCB, NULL);
  2218. }
  2219.  
  2220.  
  2221. //static
  2222. VOID HeapMonitorManager::ResumeExecutionCB (IHeapMonitorClient *client, PVOID token)
  2223. {
  2224.     client->OnResumeExecution();
  2225. }
  2226.  
  2227.  
  2228. VOID HeapMonitorManager::SendResumingEvent ()
  2229. {
  2230.     IterateClients(HMC_UNMASKABLE_EVENTS, &ResumeExecutionCB, NULL);
  2231. }
  2232.  
  2233.  
  2234. //static
  2235. VOID HeapMonitorManager::SendClosingEventCB (IHeapMonitorClient *client, PVOID token)
  2236. {
  2237.     client->OnClose();
  2238. }
  2239.  
  2240.  
  2241. VOID HeapMonitorManager::SendClosingEvent ()
  2242. {
  2243.     IterateClients(HMC_UNMASKABLE_EVENTS, &SendClosingEventCB, NULL);
  2244. }
  2245.  
  2246.  
  2247. //static
  2248. VOID HeapMonitorManager::SendThreadCreatedEventCB (IHeapMonitorClient *client, PVOID token)
  2249. {
  2250.     THREADID thd = (THREADID)token;
  2251.  
  2252.     client->OnThreadCreated(thd);
  2253. }
  2254.  
  2255.  
  2256. VOID HeapMonitorManager::SendThreadCreatedEvent (THREADID thd)
  2257. {
  2258.     IterateClients(HMC_THREAD_EVENTS, &SendThreadCreatedEventCB, (PVOID)thd);
  2259. }
  2260.  
  2261.  
  2262. //static
  2263. VOID HeapMonitorManager::SendDestroyThreadEventCB (IHeapMonitorClient *client, PVOID token)
  2264. {
  2265.     THREADID thd = (THREADID)token;
  2266.  
  2267.     client->OnDestroyThread(thd);
  2268. }
  2269.  
  2270.  
  2271. VOID HeapMonitorManager::SendDestroyThreadEvent (THREADID thd)
  2272. {
  2273.     IterateClients(HMC_THREAD_EVENTS, &SendDestroyThreadEventCB, (PVOID)thd);
  2274. }
  2275.  
  2276.  
  2277. //static
  2278. VOID HeapMonitorManager::SendPackageCreatedEventCB (IHeapMonitorClient *client, PVOID token)
  2279. {
  2280.     PKGID newpkgid = (PKGID)token;
  2281.  
  2282.     client->OnPackageCreated(newpkgid);
  2283. }
  2284.  
  2285.  
  2286. VOID HeapMonitorManager::SendPackageCreatedEvent (PKGID newpkgid)
  2287. {
  2288.     IterateClients(HMC_CLASS_EVENTS, &SendPackageCreatedEventCB, (PVOID)newpkgid);
  2289. }
  2290.  
  2291.  
  2292. //static
  2293. VOID HeapMonitorManager::SendClassLoadedEventCB (IHeapMonitorClient *client, PVOID token)
  2294. {
  2295.     CLASSID newclsid = (CLASSID)token;
  2296.  
  2297.     client->OnClassLoaded(newclsid);
  2298. }
  2299.  
  2300.  
  2301. VOID HeapMonitorManager::SendClassLoadedEvent (CLASSID newclsid)
  2302. {
  2303.     IterateClients(HMC_CLASS_EVENTS, &SendClassLoadedEventCB, (PVOID)newclsid);
  2304. }
  2305.  
  2306.  
  2307. //static
  2308. VOID HeapMonitorManager::SendUnloadClassEventCB (IHeapMonitorClient *client, PVOID token)
  2309. {
  2310.     CLASSID cls = (CLASSID)token;
  2311.  
  2312.     client->OnUnloadClass(cls);
  2313. }
  2314.  
  2315.  
  2316. VOID HeapMonitorManager::SendUnloadClassEvent (CLASSID cls)
  2317. {
  2318.     IterateClients(HMC_CLASS_EVENTS, &SendUnloadClassEventCB, (PVOID)cls);
  2319. }
  2320.  
  2321.  
  2322. //static
  2323. VOID HeapMonitorManager::RootReferencedCB (IHeapMonitorClient *client, PVOID token)
  2324. {
  2325.     RootReferencesEventInfo *pinfo = (RootReferencesEventInfo*)token;
  2326.  
  2327.     client->RootReferences(pinfo);
  2328. }
  2329.  
  2330.  
  2331. VOID HeapMonitorManager::SendRootReferencesEvent (RootReferencesEventInfo *pinfo)
  2332. {
  2333.     IterateClients(HMC_ROOT_EVENTS, &RootReferencedCB, pinfo);
  2334. }
  2335.  
  2336.  
  2337. //static
  2338. VOID HeapMonitorManager::ObjectStatusChangedCB (IHeapMonitorClient *client, PVOID token)
  2339. {
  2340.     client->OnObjectStatusChange((OBJID)token);
  2341. }
  2342.  
  2343.  
  2344. VOID HeapMonitorManager::SendObjectStatusChanged (OBJID obj)
  2345. {
  2346.     IterateClients(HMC_OBJECT_EVENTS, &ObjectStatusChangedCB, obj);
  2347. }
  2348.  
  2349.  
  2350. //static
  2351. VOID HeapMonitorManager::RootDiscoveryCompleteCB (IHeapMonitorClient *client, PVOID token)
  2352. {
  2353.     client->RootDiscoveryComplete();
  2354. }
  2355.  
  2356.  
  2357. VOID HeapMonitorManager::SendRootDiscoveryComplete ()
  2358. {
  2359.     IterateClients(HMC_HEAP_EVENTS, &RootDiscoveryCompleteCB, NULL);
  2360. }
  2361.  
  2362.  
  2363. //static
  2364. VOID HeapMonitorManager::ObjectDiscoveryCompleteCB (IHeapMonitorClient *client, PVOID token)
  2365. {
  2366.     client->ObjectDiscoveryComplete();
  2367. }
  2368.  
  2369.  
  2370. VOID HeapMonitorManager::SendObjectDiscoveryComplete ()
  2371. {
  2372.     IterateClients(HMC_HEAP_EVENTS, &ObjectDiscoveryCompleteCB, NULL);
  2373. }
  2374.  
  2375.  
  2376. VOID HeapMonitorManager::Stopped ()
  2377. {
  2378.     ASSERT(!Entered());
  2379.     ASSERT(m_flags & HMM_FL_STOPPED);
  2380.  
  2381.     WaitForSingleObject(m_hresumeevt, INFINITE);
  2382. }
  2383.  
  2384.  
  2385. CLASSID HeapMonitorManager::ClassLoaded (ClassID vmid, PWSTR name)
  2386. {
  2387.     ASSERT(!Entered());
  2388.  
  2389.     CLASSID cls = NULL;
  2390.     CLASSID ret = NULL;
  2391.  
  2392.     Enter();
  2393.     {
  2394.         ret = (CLASSID)LookupID(vmid);
  2395.         if (!ret)
  2396.         {
  2397.             cls = new(ClassIDWrapper());
  2398.             if (cls)
  2399.             {
  2400.                 BOOL success = TRUE;
  2401.                 PKGID pkgid = NULL;
  2402.  
  2403.                 PWSTR sep = name;
  2404.                 if (*sep == L'[')
  2405.                 {
  2406.                     sep++;
  2407.                     while (*sep == L'[')
  2408.                         sep++;
  2409.                     if (*sep == L'L')
  2410.                         sep++;
  2411.                 }
  2412.  
  2413.                 PWSTR pkgnamestart = sep;
  2414.                 PWCHAR pch = sep;
  2415.                 while (*pch != L'\0')
  2416.                 {
  2417.                     if (*pch == L'.' || *pch == L'/')
  2418.                     {
  2419.                         *pch = L'\0';
  2420.  
  2421.                         pkgid = LookupPackage(pkgid, pkgnamestart);
  2422.                         if (!pkgid)
  2423.                         {
  2424.                             // TODO: can continue to create class, include subpkg in name
  2425.                             success = FALSE;
  2426.                             break;
  2427.                         }
  2428.  
  2429.                         // Check if another thread created the class wrapper, in
  2430.                         // case LookupPackage left the lock.
  2431.  
  2432.                         CLASSID cls2 = (CLASSID)LookupID(vmid);
  2433.                         if (cls2)
  2434.                         {
  2435.                             ret = cls2;
  2436.                             success = FALSE;
  2437.                             break;
  2438.                         }
  2439.  
  2440.                         *pch = L'.';
  2441.                         sep = pch+1;
  2442.                     }
  2443.  
  2444.                     pch++;
  2445.                 }
  2446.  
  2447.                 if (success)
  2448.                 {
  2449.                     ASSERT(!LookupID(vmid));
  2450.  
  2451.                     if (AddID(vmid, cls))
  2452.                     {
  2453.                         cls->pkg = pkgid;
  2454.                     }
  2455.                     else
  2456.                     {
  2457.                         success = FALSE;
  2458.                     }
  2459.                 }
  2460.  
  2461.                 if (success)
  2462.                 {
  2463.                     if (name[0] == L'[')
  2464.                     {
  2465.                         cls->flags |= CID_FL_ARRAY;
  2466.  
  2467.                         if (name[1] == L'L')
  2468.                         {
  2469.                             cls->flags |= CID_FL_ARRAY_OF_OBJECTS;
  2470.                         }
  2471.                     }
  2472.  
  2473.                     if (m_flags & HMM_FL_VM_INITIALIZED)
  2474.                     {
  2475.                         success = FetchClassInfo(cls);
  2476.                     }
  2477.                 }
  2478.  
  2479.                 if (success)
  2480.                 {
  2481.                     ASSERT(cls);
  2482.  
  2483.                     ret = cls;
  2484.                 }
  2485.                 else
  2486.                 {
  2487.                     delete(cls);
  2488.                     cls = NULL;
  2489.                 }
  2490.             }
  2491.         }
  2492.     }
  2493.     Leave();
  2494.  
  2495.     if (cls)
  2496.         SendClassLoadedEvent(cls);
  2497.  
  2498.     return ret;
  2499. }
  2500.  
  2501.  
  2502. CLASSID HeapMonitorManager::ClassLoaded (ClassID vmid)
  2503. {
  2504.     ASSERT(!Entered());
  2505.  
  2506.     CLASSID cls = NULL;
  2507.  
  2508.     PSTR pclsname;
  2509.     HRESULT hr = m_vminfo->ClassInformation(
  2510.             vmid,
  2511.             &pclsname,
  2512.             NULL, // source file
  2513.             NULL, // methods count
  2514.             NULL, // methods
  2515.             NULL); // instance creation count
  2516.     if (SUCCEEDED(hr) && pclsname)
  2517.     {
  2518.         PWSTR pwclsname;
  2519.  
  2520.         hr = Utf8ToUnicode(pclsname, &pwclsname);
  2521.  
  2522.         if (SUCCEEDED(hr) && pwclsname)
  2523.         {
  2524.             cls = ClassLoaded(vmid, pwclsname);
  2525.  
  2526.             delete(pwclsname);
  2527.         }
  2528.  
  2529.         CoTaskMemFree(pclsname);
  2530.     }
  2531.  
  2532.     return cls;
  2533. }
  2534.  
  2535.  
  2536. VOID HeapMonitorManager::ClassUnloaded (ClassID vmid)
  2537. {
  2538.     CLASSID cls = (CLASSID)LookupID(vmid);
  2539.     if (cls)
  2540.     {
  2541.         SendUnloadClassEvent(cls);
  2542.  
  2543.         delete cls;
  2544.     }
  2545. }
  2546.  
  2547.  
  2548. THREADID HeapMonitorManager::ThreadCreated (ThreadID vmid, BOOL ghost)
  2549. {
  2550.     THREADID id;
  2551.  
  2552.     Enter();
  2553.     {
  2554.         id = (THREADID)LookupID(vmid);
  2555.         if (!id)
  2556.         {
  2557.             id = new(ThreadIDWrapper());
  2558.             if (id)
  2559.             {
  2560.                 if (AddID(vmid, id))
  2561.                 {
  2562.                     if (ghost)
  2563.                         id->type = ID_GHOST_THREAD;
  2564.                 }
  2565.                 else
  2566.                 {
  2567.                     delete(id);
  2568.                     id = NULL;
  2569.                 }
  2570.             }
  2571.         }
  2572.         else if (!ghost)
  2573.         {
  2574.             ASSERT(id->type == ID_GHOST_THREAD);
  2575.             id->type = ID_THREAD;
  2576.         }
  2577.     }
  2578.     Leave();
  2579.  
  2580.     if (id && !ghost)
  2581.     {
  2582.         SendThreadCreatedEvent(id);
  2583.     }
  2584.  
  2585.     return id;
  2586. }
  2587.  
  2588.  
  2589. HRESULT HeapMonitorManager::ThreadNameChanged (ThreadID vmid, PWSTR newname)
  2590. {
  2591.     // TODO
  2592.     return E_NOTIMPL;
  2593. }
  2594.  
  2595.  
  2596. VOID HeapMonitorManager::ThreadDestroyed (ThreadID vmid)
  2597. {
  2598.     THREADID thdid = NULL;
  2599.  
  2600.     // Remove it from the map, serializing with IterateIDs and heap dumping.
  2601.  
  2602.     Enter();
  2603.     {
  2604.         thdid = (THREADID)LookupID(vmid);
  2605.         if (thdid)
  2606.         {
  2607.             if (m_flags & HMM_FL_STOPPED)
  2608.             {
  2609.                 thdid->flags |= TID_FL_DEAD;
  2610.                 thdid = NULL;
  2611.             }
  2612.             else
  2613.             {
  2614.                 DeleteID(thdid);
  2615.             }
  2616.         }
  2617.     }
  2618.     Leave();
  2619.  
  2620.     if (thdid)
  2621.     {
  2622.         // Clients can no longer "discover" the thread, but they may still
  2623.         // have references to it.  Notify clients that the ID is about to be
  2624.         // deleted.
  2625.  
  2626.         SendDestroyThreadEvent(thdid);
  2627.  
  2628.         delete(thdid);
  2629.     }
  2630. }
  2631.  
  2632.  
  2633. //static
  2634. int HeapMonitorManager::MarkEmptyRootsCB (ID id, PVOID token)
  2635. {
  2636. #ifndef NDEBUG
  2637.     HeapMonitorManager *hmm = (HeapMonitorManager*)token;
  2638.     ASSERT(hmm->Entered());
  2639. #endif // !NDEBUG
  2640.     
  2641.     if (id->type >= ID_FIRST_TRANSIENT)
  2642.     {
  2643.         BOOL fReport = FALSE;
  2644.         
  2645.         switch (id->type)
  2646.         {
  2647.         case ID_ROOT:
  2648.             ROOTID rootid;
  2649.             rootid = (ROOTID)id;
  2650.             fReport = !(rootid->flags & RID_FL_HAS_REFERENCES);
  2651.             break;
  2652.             
  2653.         case ID_STACKFRAME:
  2654.             STACKID stkid;
  2655.             stkid = (STACKID)id;
  2656.             fReport = !(stkid->flags & SID_FL_HAS_REFERENCES);
  2657.             break;
  2658.         }
  2659.  
  2660.         if (fReport)
  2661.             id->flags |= ID_FL_MARKED_EMPTY_ROOT;
  2662.     }
  2663.     
  2664.     return 1;
  2665. }
  2666.  
  2667.  
  2668. //static
  2669. int HeapMonitorManager::ReportEmptyRootsCB (ID id, PVOID token)
  2670. {
  2671.     HeapMonitorManager *hmm = (HeapMonitorManager*)token;
  2672.  
  2673.     ASSERT(!hmm->Entered());
  2674.     
  2675.     if (id->flags & ID_FL_MARKED_EMPTY_ROOT)
  2676.     {
  2677.         hmm->Enter();
  2678.         {
  2679.             id->flags = ((id->flags & ~ID_FL_MARKED_EMPTY_ROOT) | ID_FL_REPORTED_EMPTY_ROOT);
  2680.         }
  2681.         hmm->Leave();
  2682.     
  2683.         RootReferencesEventInfo info;
  2684.  
  2685.         switch (id->type)
  2686.         {
  2687.         case ID_ROOT:
  2688.             ROOTID rootid;
  2689.             rootid = (ROOTID)id;
  2690.             if (!(rootid->flags & RID_FL_HAS_REFERENCES))
  2691.             {
  2692.                 info.type = rootid->roottype;
  2693.                 info.id1 = rootid->rootid1;
  2694.                 info.id2 = rootid->rootid2;
  2695.             }
  2696.             break;
  2697.             
  2698.         case ID_STACKFRAME:
  2699.             STACKID stkid;
  2700.             stkid = (STACKID)id;
  2701.             if (!(stkid->flags & SID_FL_HAS_REFERENCES))
  2702.             {
  2703.                 info.type = stkid->frmtype;
  2704.                 info.id1 = stkid->vmid;
  2705.                 info.id2 = stkid->methodid;
  2706.             }
  2707.             break;
  2708.  
  2709.         default:
  2710.             ASSERT(!"unknown marked id type");
  2711.             return 1;
  2712.         }
  2713.  
  2714.         info.nrefs = 0;
  2715.         info.rgrefs = NULL;
  2716.         info.rgflags = NULL;
  2717.         info.rootid = id;
  2718.  
  2719.         hmm->IterateClients(HMC_ROOT_EVENTS, &RootReferencedCB, &info);
  2720.     }
  2721.     
  2722.     return 1;
  2723. }
  2724.  
  2725.  
  2726. //static
  2727. int HeapMonitorManager::ResetEmptyRootsCB (ID id, PVOID token)
  2728. {
  2729.     ASSERT(!(id->flags & ID_FL_MARKED_EMPTY_ROOT));
  2730.     
  2731.     id->flags &= ~ID_FL_REPORTED_EMPTY_ROOT;
  2732.  
  2733.     return 1;
  2734. }
  2735.  
  2736.  
  2737. //------------------------------------------------------------------------
  2738.  
  2739.  
  2740. STDMETHODIMP HeapMonitorManager::Initialize (
  2741.         LPCSTR pclass_file_name,
  2742.         IJavaEventMonitorIDInfo *pmonitor_info,
  2743.         DWORD java_flags,
  2744.         DWORD *prequested_events)
  2745. {
  2746.     HRESULT hr;
  2747.  
  2748.     hr = pmonitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo2, (PVOID*)&m_vminfo);
  2749.     
  2750.     if (hr == S_OK)
  2751.     {
  2752.         hr = pmonitor_info->QueryInterface(IID_IJavaHeapMonitor, (PVOID*)&m_vmheapmon);
  2753.     }
  2754.  
  2755.     if (hr == S_OK)
  2756.     {
  2757.         // Ignore failure.
  2758.         pmonitor_info->QueryInterface(IID_IJavaHeapMonitor2, (PVOID*)&m_vmheapmon2);
  2759.     }
  2760.  
  2761.     if (hr == S_OK)
  2762.     {
  2763.         IHeapInfoCallback *heapcb;
  2764.         hr = QueryInterface(IID_IHeapInfoCallback, (PVOID*)&heapcb);
  2765.         if (hr == S_OK)
  2766.         {
  2767.             hr = m_vmheapmon->GetHeapInfo(heapcb);
  2768.             heapcb->Release();
  2769.         }
  2770.     }
  2771.     
  2772.     if (hr == S_OK)
  2773.     {
  2774.         DWORD caps;
  2775.         hr = m_vmheapmon->ModifyHeapMonitorCapabilities(JVM_HEAPMON_OBJECT_AGE, TRUE, &caps);
  2776.         if (SUCCEEDED(hr) && (caps & JVM_HEAPMON_OBJECT_AGE))
  2777.             m_flags |= HMM_FL_OBJECT_AGING;
  2778.  
  2779.         hr = S_OK;
  2780.     }
  2781.  
  2782.     if (hr == S_OK)
  2783.     {
  2784.         IJavaEventMonitorIDInfo4 *pinfo4;
  2785.         if (pmonitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo4, (PVOID*)&pinfo4) == S_OK)
  2786.         {
  2787.             pinfo4->SetMonitorInitializationOptions(  JVM_INIT_OPT_FP_SAFE_METHOD_CALLS
  2788.                                                     | JVM_INIT_OPT_GC_SAFE_METHOD_CALLS
  2789.                                                     | JVM_INIT_OPT_RETURN_VALUE_NOT_NEEDED
  2790.                                                     | JVM_INIT_OPT_WONT_TOGGLE_METHOD_CALL_EVENTS);
  2791. //                                                    | JVM_INIT_OPT_DONT_NEED_ALLOCATION_CALLBACK);
  2792.  
  2793.             pinfo4->Release();
  2794.         }
  2795.     }
  2796.  
  2797.     *prequested_events = JVM_MONITOR_CLASS_LOADS | JVM_MONITOR_THREADS;
  2798.  
  2799.     // Only S_OK is respected by the VM.
  2800.     if (hr != S_OK)
  2801.         ASSERT(!"heap monitor failed to initialize");
  2802.  
  2803.     return hr;
  2804. }
  2805.  
  2806.  
  2807. STDMETHODIMP HeapMonitorManager::NotifyEvent (JVM_EVENT_TYPE event, UniqueID event_id)
  2808. {
  2809.     HRESULT hr = E_FAIL;
  2810.  
  2811.     switch (event)
  2812.     {
  2813.     case JVM_EVENT_TYPE_THREAD_CREATE:
  2814.         if (ThreadCreated((ThreadID)event_id, FALSE))
  2815.             hr = S_OK;
  2816.         break;
  2817.  
  2818.     case JVM_EVENT_TYPE_THREAD_DESTROY:
  2819.         ThreadDestroyed((ThreadID)event_id);
  2820.         hr = S_OK;
  2821.         break;
  2822.  
  2823.     case JVM_EVENT_TYPE_CLASS_LOAD_FINISHED:
  2824.         if (ClassLoaded((ClassID)event_id))
  2825.             hr = S_OK;
  2826.         break;
  2827.  
  2828.     case JVM_EVENT_TYPE_CLASS_UNLOAD:
  2829.         ClassUnloaded((ClassID)event_id);
  2830.         hr = S_OK;
  2831.         break;
  2832.  
  2833.     case JVM_EVENT_TYPE_GC_STARTED:
  2834.     case JVM_EVENT_TYPE_GC_FINISHED:
  2835.         if (m_flags & HMM_FL_CLOSED)
  2836.             DestroyNow();
  2837.         hr = S_OK;
  2838.         break;
  2839.     }
  2840.  
  2841.     return hr;
  2842. }
  2843.  
  2844.  
  2845. STDMETHODIMP HeapMonitorManager::MethodEntry (MethodID method_id, StackID stack_id)
  2846. {
  2847.     return E_FAIL;
  2848. }
  2849.  
  2850.  
  2851. STDMETHODIMP HeapMonitorManager::MethodExit (StackID stack_id)
  2852. {
  2853.     return E_FAIL;
  2854. }
  2855.  
  2856.  
  2857. STDMETHODIMP HeapMonitorManager::ExecuteByteCode (MethodID method_id, BYTE_CODE *pbyte_code, DWORD byte_code_offset)
  2858. {
  2859.     return E_FAIL;
  2860. }
  2861.  
  2862.  
  2863. STDMETHODIMP HeapMonitorManager::ExecuteSourceLine (MethodID method_id, DWORD line_number)
  2864. {
  2865.     return E_FAIL;
  2866. }
  2867.  
  2868.  
  2869. STDMETHODIMP HeapMonitorManager::NotifyEvent2 (JVM_EVENT_TYPE2 event2, UniqueID first_event_id, UniqueID second_event_id)
  2870. {
  2871.     HRESULT hr = E_FAIL;
  2872.  
  2873.     switch (event2)
  2874.     {
  2875.     case JVM_EVENT_TYPE2_INITIALIZED:
  2876.         Enter();
  2877.         {
  2878.             IterateIDs_Safe(&FetchClassInfoCB, this);
  2879.             m_flags |= HMM_FL_VM_INITIALIZED;
  2880.         }
  2881.         Leave();
  2882.         hr = S_OK;
  2883.         break;
  2884.     }
  2885.     
  2886.     return hr;
  2887. }
  2888.  
  2889.  
  2890. STDMETHODIMP HeapMonitorManager::MethodExit2 (MethodID method_id, StackID stack_id)
  2891. {
  2892.     return E_FAIL;
  2893. }
  2894.  
  2895.  
  2896. STDMETHODIMP HeapMonitorManager::GetPossibleEventCategories (DWORD *ppossible_events)
  2897. {
  2898.     *ppossible_events = JVM_MONITOR_CLASS_LOADS | JVM_MONITOR_THREADS;
  2899.     return S_OK;
  2900. }
  2901.  
  2902.  
  2903. #ifdef DEBUG
  2904.  
  2905. int CountMultiRefObjects (ID id, PVOID token)
  2906. {
  2907.     unsigned *pcount = (unsigned*)token;
  2908.  
  2909.     if (id->type == ID_OBJECT)
  2910.     {
  2911.         OBJID obj = (OBJID)id;
  2912.  
  2913.         if (obj->flags & OID_FL_MULTIPLE_REFERENCES)
  2914.         {
  2915.             *pcount = *pcount + 1;
  2916.         }
  2917.     }
  2918.  
  2919.     return 1;
  2920. }
  2921.  
  2922. #endif // DEBUG
  2923.  
  2924.  
  2925. STDMETHODIMP HeapMonitorManager::BeginContainer (CONTAINER_TYPE type, UniqueID id1, UniqueID id2)
  2926. {
  2927.     HRESULT hr = S_OK;
  2928.  
  2929.     ID rootid = NULL;
  2930.     
  2931.     switch (type)
  2932.     {
  2933.     case C_BEGIN:
  2934.     {
  2935.         BOOL fSendSuspendedEvent = FALSE;
  2936.         ULONG NumTrackedObjectChanges = 0;
  2937.     
  2938.         Enter();
  2939.         {
  2940. #ifdef DEBUG
  2941.             m_HeapDumpThreadId = GetCurrentThreadId();
  2942. #endif // DEBUG
  2943.  
  2944.             DWORD newflags = m_flags;
  2945.  
  2946.             m_HeapInfoNeeded = m_InfoMaskUnion;
  2947.  
  2948.             if (newflags & HMM_FL_CLOSED)
  2949.                 ASSERT(!(newflags & HMM_FL_STOP));
  2950.  
  2951.             if (newflags & HMM_FL_STOP)
  2952.             {
  2953.                 newflags = (newflags & ~HMM_FL_STOP) | HMM_FL_STOPPED;
  2954.  
  2955.                 m_HeapInfoNeeded |= m_StoppedInfoMaskUnion;
  2956.  
  2957.                 fSendSuspendedEvent = TRUE;
  2958.             }
  2959.  
  2960.             newflags = (newflags & ~HMM_FL_HEAP_EXPLORED) | HMM_FL_EXPLORING_HEAP;
  2961.  
  2962.             m_flags = newflags;
  2963.  
  2964.             ZeroMemory(&m_gcinfo, FIELD_OFFSET(PerGCInformation, prev));
  2965.  
  2966.             m_gcinfo.iGC = ++m_iGC;
  2967.  
  2968.             if (fSendSuspendedEvent)
  2969.             {
  2970.                 // Before notifying clients, update any OBJID's that were kept
  2971.                 // from the last gc.
  2972.  
  2973.                 for (TrackedObjectList *trkent = m_trackedobjs; trkent; trkent = trkent->next)
  2974.                 {
  2975.                     if (trkent->vmhid)
  2976.                     {
  2977.                         OBJID obj = trkent->obj;
  2978.                         ASSERT(!(obj->flags & OID_FL_DEAD));
  2979.                     
  2980.                         ObjectID vmid = obj->GetObjectID();
  2981.  
  2982.                         EVAL(m_vminfo->GetObjectsFromHandles(1, &trkent->vmhid, &obj->vmid) == S_OK);
  2983.  
  2984.                         if (obj->vmid)
  2985.                         {
  2986.                             trkent->fStatusChanged = (obj->vmid != vmid);
  2987.                         }
  2988.                         else
  2989.                         {
  2990.                             // VM automatically cleans this up
  2991.                             ASSERT(!trkent->vmhid);
  2992.  
  2993.                             trkent->fStatusChanged = TRUE;
  2994.                         
  2995.                             obj->flags |= OID_FL_DEAD;
  2996.                             
  2997.                             TRASH(obj->vmid);
  2998.  
  2999.                             m_idmap.DeleteID(vmid);
  3000.                             m_IDMapChangeCount++;
  3001.                         }
  3002.  
  3003.                         if (trkent->fStatusChanged)
  3004.                             NumTrackedObjectChanges++;
  3005.                     }
  3006.                 }
  3007.             }
  3008.  
  3009.             if (!(m_HeapInfoNeeded & HMC_ALL_HEAPCB_INFO))
  3010.             {
  3011.                 // No information collected via IHeapInfoCallback is needed.
  3012.                 // We'll get a C_END notification but nothing more.
  3013.                 hr = E_FAIL;
  3014.             }
  3015.  
  3016.             // When we leave the lock, new clients will see we're in a stopped
  3017.             // state, so the ids need to already be cleaned up.
  3018.  
  3019.             m_idmap.FilterIDs(&ResetPerGCIDInfo, this);
  3020.         }
  3021.         Leave();
  3022.  
  3023.         if (m_HeapInfoNeeded)
  3024.         {
  3025.             StartHeapDumpProgressIndicator();
  3026.  
  3027.             SetStatusText("Collecting heap roots...");
  3028.         }
  3029.  
  3030.         if (fSendSuspendedEvent)
  3031.         {
  3032.             SendSuspendedEvent();
  3033.         }
  3034.  
  3035.         // Report any changes in tracked objects.
  3036.  
  3037.         while (NumTrackedObjectChanges)
  3038.         {
  3039.             Enter();
  3040.             {
  3041.                 for (TrackedObjectList *trkent = m_trackedobjs; trkent; trkent = trkent->next)
  3042.                 {
  3043.                     if (trkent->fStatusChanged)
  3044.                     {
  3045.                         trkent->fStatusChanged = FALSE;
  3046.  
  3047.                         Leave();
  3048.                         {
  3049.                             NumTrackedObjectChanges--;
  3050.                             IncProgressIndicator();
  3051.                         
  3052.                             SendObjectStatusChanged(trkent->obj);
  3053.                         }
  3054.                         Enter();
  3055.  
  3056.                         break;
  3057.                     }
  3058.                 }
  3059.             }
  3060.             Leave();
  3061.         }
  3062.  
  3063.         m_lastthreadid = NULL;
  3064.  
  3065.         break;
  3066.     }
  3067.  
  3068.     case C_END:
  3069.         {
  3070.             m_gcinfo.InfoMaskCollected = (m_HeapInfoNeeded & ~HMC_INFO_COUNT_MONITORS);
  3071.  
  3072.             if (m_InfoMaskUnion & HMC_INFO_COUNT_MONITORS)
  3073.             {
  3074.                 if (m_vminfo->GetMonitorUsage(&m_gcinfo.nObjectMonitors) == S_OK)
  3075.                     m_gcinfo.InfoMaskCollected |= HMC_INFO_COUNT_MONITORS;
  3076.             }
  3077.  
  3078. #ifdef DEBUG
  3079.             unsigned count = 0;
  3080.             IterateIDs_Safe(&CountMultiRefObjects, &count);
  3081.             ASSERT(count == m_gcinfo.nObjectsWithMultipleReferences);
  3082. #endif // DEBUG
  3083.  
  3084.             if (m_gcinfo.InfoMaskCollected)
  3085.             {
  3086.                 PerGCInformation *info = new(PerGCInformation());
  3087.                 if (info)
  3088.                 {
  3089.                     CopyMemory(info, &m_gcinfo, sizeof(m_gcinfo));
  3090.                     if (info->next)
  3091.                         info->next->prev = info;
  3092.                     m_gcinfo.next = info;
  3093.                 }
  3094.             }
  3095.  
  3096.             SendObjectDiscoveryComplete();
  3097.             
  3098.             BOOL fChangedToRunning = FALSE;
  3099.  
  3100.             Enter();
  3101.             {
  3102.                 m_flags = (m_flags & ~HMM_FL_EXPLORING_HEAP) | HMM_FL_HEAP_EXPLORED;
  3103.  
  3104.                 BOOL fStopped = (m_flags & HMM_FL_STOPPED);
  3105.  
  3106.                 Leave();
  3107.                 {
  3108.                     StopHeapDumpProgressIndicator();
  3109.  
  3110.                     if (fStopped)
  3111.                     {
  3112.                         if (!(m_flags & HMM_FL_INACCURATE))
  3113.                         {
  3114.                             CHAR buf[200];
  3115.                             if (m_gcinfo.InfoMaskCollected & HMC_INFO_HEAP_OBJECTS)
  3116.                             {
  3117.                                 wsprintf(buf, "Heap dump completed.  %u objects, %u bytes.",
  3118.                                         m_gcinfo.GetTotalNumObjects(), m_gcinfo.GetTotalSizeOfObjects());
  3119.                             }
  3120.                             else
  3121.                             {
  3122.                                 wsprintf(buf, "Heap dump completed.");
  3123.                             }
  3124.                             SetStatusText(buf);
  3125.                         }
  3126.                         else
  3127.                         {
  3128.                             SetStatusText("Heap dump finished...but errors occurred and information may not be complete.");
  3129.                         }
  3130.                     
  3131.                         IndicateStopped();
  3132.                         
  3133.                         for (;;)
  3134.                         {
  3135.                             Stopped();
  3136.  
  3137.                             Enter();
  3138.                             {
  3139.                                 for (;;)
  3140.                                 {
  3141.                                     PendingHeapWalk *heapwalk = m_heapwalks;
  3142.                                     if (!heapwalk)
  3143.                                         break;
  3144.  
  3145.                                     m_heapwalks = NULL;
  3146.  
  3147.                                     Leave();
  3148.                                     {
  3149.                                         if (!(m_flags & HMM_FL_PROGRESS_INDICATOR))
  3150.                                         {
  3151.                                             if (StartHeapDumpProgressIndicator())
  3152.                                                 SetStatusText("Searching...");
  3153.                                         }
  3154.  
  3155.                                         do
  3156.                                         {
  3157.                                             if (heapwalk->cb->BeginDump() == S_OK)
  3158.                                             {
  3159.                                                 m_vmheapmon2->WalkHeap(heapwalk->cb, heapwalk->HeapWalkFlags);
  3160.  
  3161.                                                 heapwalk->cb->EndDump();
  3162.                                             }
  3163.  
  3164.                                             heapwalk->cb->Release();
  3165.  
  3166.                                             PendingHeapWalk *trash = heapwalk;
  3167.                                             heapwalk = heapwalk->next;
  3168.                                             delete(trash);
  3169.                                         }
  3170.                                         while (heapwalk);
  3171.                                     }
  3172.                                     Enter();
  3173.                                 }
  3174.  
  3175.                                 if (m_flags & HMM_FL_PROGRESS_INDICATOR)
  3176.                                 {
  3177.                                     Leave();
  3178.                                     {
  3179.                                         StopHeapDumpProgressIndicator();
  3180.  
  3181.                                         SetStatusText("Search complete.");
  3182.                                     }
  3183.                                     Enter();
  3184.                                 }
  3185.  
  3186.                                 if (m_flags & HMM_FL_GO)
  3187.                                     goto entered;
  3188.                             }
  3189.                             Leave();
  3190.                         }
  3191.  
  3192.                         //Enter();
  3193.                     entered:
  3194.                         ASSERT(Entered());
  3195.                         
  3196.                         m_flags &= ~(HMM_FL_STOPPED | HMM_FL_HEAP_EXPLORED | HMM_FL_GO | HMM_FL_INACCURATE);
  3197.                         fChangedToRunning = TRUE;
  3198.                     }
  3199.                     else
  3200.                     {
  3201.                         Enter();
  3202.                     }
  3203.                 }
  3204.                 ASSERT(Entered());
  3205.  
  3206. #ifdef DEBUG
  3207.                 m_HeapDumpThreadId = INVALID_THREAD_ID;
  3208. #endif // DEBUG
  3209.             }
  3210.             Leave();
  3211.  
  3212.             // The STOPPED flag must be cleared before notifying clients.  New
  3213.             // clients created in this time window will pick this up and not
  3214.             // pre-populate themselves with soon-to-be-stale state.  We will
  3215.             // block until the client is created when attempting to send them
  3216.             // notification that we are resuming.
  3217.  
  3218.             if (fChangedToRunning)
  3219.             {
  3220.                 SendResumingEvent();
  3221.                 
  3222.                 IndicateRunning();
  3223.             }
  3224.  
  3225.             SetStatusText("");
  3226.  
  3227.             if (m_HeapInfoNeeded & HMC_ALL_HEAPCB_INFO)
  3228.             {
  3229.                 // Now that all clients see that we are in a running state, we
  3230.                 // can do this outside the lock.
  3231.             
  3232.                 m_rootrefs.Reset();
  3233.  
  3234.                 m_idmap.FilterIDs(&DeleteTransientIDs, this);
  3235.             }
  3236.  
  3237.             if (m_flags & HMM_FL_CLOSED)
  3238.                 DestroyNow();
  3239.         }
  3240.         break;
  3241.  
  3242.     case C_RT_THREAD:
  3243.     case C_RT_CLASS:
  3244.     case C_RT_JIT:
  3245.     case C_RT_NATIVE:
  3246.     case C_RT_NATIVEGC:
  3247.     case C_RT_COM:
  3248.     case C_RT_INTERPRETED:
  3249.     case C_RT_FASTINTERPRETED:
  3250.     case C_RT_INTERNALFRAME:
  3251.         if (m_HeapInfoNeeded & HMC_INFO_HEAP_ROOTS)
  3252.         {
  3253.             rootid = DiscoveredRoot(type, id1, id2);
  3254.             if (rootid)
  3255.             {
  3256.                 if (rootid->type == ID_THREAD || rootid->type == ID_GHOST_THREAD)
  3257.                     m_lastthreadid = (THREADID)rootid;
  3258.             }
  3259.             else
  3260.             {
  3261.                 hr = E_OUTOFMEMORY;
  3262.             }
  3263.         }
  3264.         break;
  3265.  
  3266.     case C_HEAP:
  3267.  
  3268.         if (m_HeapInfoNeeded & HMC_INFO_HEAP_ROOTS)
  3269.         {
  3270.             // If a container has no references, we may never get a
  3271.             // RootReferences call for it, so clients never get an
  3272.             // AddRootReferences call, so clients may never know about the
  3273.             // root.
  3274.  
  3275.             Enter();
  3276.             {
  3277.                 ULONG changestart;
  3278.  
  3279.                 if (IsEventRequested(HMC_ROOT_EVENTS))
  3280.                 {
  3281.                     ULONG newchangecount = m_IDMapChangeCount;
  3282.  
  3283.                     do
  3284.                     {
  3285.                         changestart = newchangecount;
  3286.  
  3287.                         IterateIDs_Safe(&MarkEmptyRootsCB, this);
  3288.  
  3289.                         Leave();
  3290.                         {
  3291.                             IterateIDs_Safe(&ReportEmptyRootsCB, this);
  3292.                         }
  3293.                         Enter();
  3294.  
  3295.                         newchangecount = m_IDMapChangeCount;
  3296.                     }
  3297.                     while (changestart != newchangecount);
  3298.  
  3299.                     IterateIDs_Safe(&ResetEmptyRootsCB, this);
  3300.                 }
  3301.             }
  3302.             Leave();
  3303.  
  3304.             SendRootDiscoveryComplete();
  3305.         }
  3306.         
  3307.         if (m_flags & HMM_FL_STOPPED)
  3308.         {
  3309.             SetStatusText("Examining heap objects...");
  3310.         }
  3311.  
  3312.         if (!(m_HeapInfoNeeded & (HMC_INFO_HEAP_OBJECTS | HMC_INFO_HEAP_OBJECT_REFS)))
  3313.         {
  3314.             hr = E_FAIL;
  3315.         }
  3316.         
  3317.         break;
  3318.  
  3319.     default:
  3320.         // For any other container type, don't know how to interpret the ids.
  3321.         if (m_HeapInfoNeeded & HMC_INFO_HEAP_ROOTS)
  3322.         {
  3323.             rootid = DiscoveredRoot(type, id1, NULL);
  3324.             if (rootid)
  3325.                 ;
  3326.             else
  3327.                 hr = E_OUTOFMEMORY;
  3328.         }
  3329.         break;
  3330.     }
  3331.  
  3332.     m_lastroottype = type;
  3333.     m_lastrootvmid1 = id1;
  3334.     m_lastrootvmid2 = id2;
  3335.     m_lastrootid = rootid;
  3336.  
  3337.     IncProgressIndicator();
  3338.  
  3339.     if (FAILED(hr) && type != C_BEGIN && type != C_HEAP)
  3340.     {
  3341.         Enter();
  3342.         {
  3343.             m_flags |= HMM_FL_INACCURATE;
  3344.         }
  3345.         Leave();
  3346.  
  3347.         hr = S_OK;
  3348.     }
  3349.  
  3350.     if (hr == S_OK)
  3351.     {
  3352.         if (!(m_HeapInfoNeeded & HMC_INFO_HEAP_ROOT_REFS) && type != C_HEAP)
  3353.         {
  3354.             hr = S_POSTPONE_REFERENCES;
  3355.         }
  3356.     }
  3357.  
  3358.     // TODO: allow user to cancel heap dump
  3359.     
  3360.     return hr;
  3361. }
  3362.  
  3363.  
  3364. STDMETHODIMP HeapMonitorManager::RootReferences (const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
  3365. {
  3366.     if (m_HeapInfoNeeded & HMC_INFO_HEAP_ROOT_REFS)
  3367.     {
  3368.         RootReferencesEventInfo info;
  3369.         info.type = m_lastroottype;
  3370.         info.id1 = m_lastrootvmid1;
  3371.         info.id2 = m_lastrootvmid2;
  3372.         info.nrefs = nrefs;
  3373.         info.rgrefs = prefs;
  3374.         info.rgflags = pflags;
  3375.         info.rootid = m_lastrootid;
  3376.  
  3377.         for (unsigned i = 0; i < nrefs; i++)
  3378.         {
  3379.             ObjectID vmid = prefs[i];
  3380.             if (vmid)
  3381.             {
  3382.                 m_gcinfo.nRootEdges++;
  3383.                 m_gcinfo.rgcRootReferences[info.type - C_FIRST - 1]++;
  3384.  
  3385.                 OBJID id = DiscoveredObject(vmid);
  3386.  
  3387.                 Enter();
  3388.                 {
  3389.                     if (id)
  3390.                     {
  3391.                         id->flags |= OID_FL_REFERENCED_BY_ROOT;
  3392.                     }
  3393.                     else
  3394.                     {
  3395.                         m_flags |= HMM_FL_INACCURATE;
  3396.                     }
  3397.                 }
  3398.                 Leave();
  3399.             }
  3400.         }
  3401.  
  3402.         if (m_lastrootid)
  3403.         {
  3404.             if (m_lastrootid->type == ID_ROOT)
  3405.                 ((ROOTID)m_lastrootid)->flags |= RID_FL_HAS_REFERENCES;
  3406.             else if (m_lastrootid->type == ID_STACKFRAME)
  3407.                 ((STACKID)m_lastrootid)->flags |= SID_FL_HAS_REFERENCES;
  3408.         
  3409.             m_rootrefs.AddRootReferences(m_lastrootid, nrefs, prefs);
  3410.  
  3411.             SendRootReferencesEvent(&info);
  3412.         }
  3413.     }
  3414.  
  3415.     // TODO: allow user to cancel heap dump
  3416.     
  3417.     return S_POSTPONE_REFERENCES;
  3418. }
  3419.  
  3420.  
  3421. STDMETHODIMP HeapMonitorManager::ObjectReferences (ObjectID vmid, DWORD flags, const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
  3422. {
  3423.     ASSERT(m_HeapInfoNeeded & (HMC_INFO_HEAP_OBJECTS | HMC_INFO_HEAP_OBJECT_REFS));
  3424.  
  3425.     if (m_HeapInfoNeeded & HMC_INFO_HEAP_OBJECT_REFS)
  3426.     {
  3427.         BOOL fAnyStatusChange = FALSE;
  3428.     
  3429.         Enter();
  3430.         {
  3431.             OBJID id = (OBJID)LookupID(vmid);
  3432.  
  3433.             // See below...
  3434.             if (!(flags & JVM_OBJ_ALREADY_REPORTED))
  3435.             {
  3436.                 if (!id)
  3437.                     id = CreateOBJID(vmid);
  3438.                 if (id)
  3439.                     id->flags |= OID_FL_VISITED_BEFORE_REPORTED;
  3440.             }
  3441.  
  3442.             if (id)
  3443.             {
  3444.                 // Indicate to ExpandObject not to hash references from this
  3445.                 // object.
  3446.                 id->flags |= OID_FL_EXPANDED;
  3447.             }
  3448.  
  3449.             for (unsigned i = 0; i < nrefs; i++)
  3450.             {
  3451.                 ObjectID refvmid = prefs[i];
  3452.                 if (refvmid)
  3453.                 {
  3454.                     m_gcinfo.nObjectEdges++;
  3455.  
  3456.                     OBJID refid = (OBJID)LookupID(refvmid);
  3457.                     if (refid)
  3458.                     {
  3459.                         DWORD oldflags = refid->flags;
  3460.                         DWORD newflags = oldflags;
  3461.                         
  3462.                         newflags |= ID_FL_DISCOVERED;
  3463.                     
  3464.                         if (   (pflags[i] & JVM_OBJ_ALREADY_REPORTED)
  3465.                             && !(oldflags & OID_FL_MULTIPLE_REFERENCES))
  3466.                         {
  3467.                             // If the object is visited before its first
  3468.                             // reference is discovered, it will be marked
  3469.                             // REPORTED for its first reference.  We've
  3470.                             // detected this special case above, this magic bit
  3471.                             // means to treat this reference as the object's
  3472.                             // first reference.
  3473.                             //
  3474.                             // This is a consequence of using
  3475.                             // S_POSTPONE_REFERENCES to perform the heap dump.
  3476.                             // If S_OK was returned, this would not be
  3477.                             // necessary, since it would be impossible to
  3478.                             // discover an object before at least one of its
  3479.                             // referring objects is discovered.
  3480.                             
  3481.                             if (!(oldflags & OID_FL_VISITED_BEFORE_REPORTED))
  3482.                             {
  3483.                                 newflags |= OID_FL_MULTIPLE_REFERENCES;
  3484.                                 m_gcinfo.nObjectsWithMultipleReferences++;
  3485.                             }
  3486.                             else
  3487.                             {
  3488.                                 newflags &= ~OID_FL_VISITED_BEFORE_REPORTED;
  3489.                             }
  3490.                         }
  3491.  
  3492.                         refid->flags = newflags;
  3493.                         
  3494.                         if (oldflags != newflags)
  3495.                             fAnyStatusChange = TRUE;
  3496.                     }
  3497.                     else
  3498.                     {
  3499.                         if (pflags[i] & JVM_OBJ_ALREADY_REPORTED)
  3500.                         {
  3501.                             refid = CreateOBJID(refvmid);
  3502.                             if (refid)
  3503.                             {
  3504.                                 refid->flags |= ID_FL_DISCOVERED | OID_FL_MULTIPLE_REFERENCES;
  3505.  
  3506.                                 m_gcinfo.nObjectsWithMultipleReferences++;
  3507.  
  3508.                                 fAnyStatusChange = TRUE;
  3509.                             }
  3510.                         }
  3511.                     }
  3512.                 }
  3513.             }
  3514.         }
  3515.         Leave();
  3516.  
  3517.         if (fAnyStatusChange)
  3518.         {
  3519.             for (unsigned i = 0; i < nrefs; i++)
  3520.             {
  3521.                 ObjectID refvmid = prefs[i];
  3522.                 if (refvmid)
  3523.                 {
  3524.                     OBJID refid = (OBJID)LookupID(refvmid);
  3525.                     if (refid)
  3526.                     {
  3527.                         SendObjectStatusChanged(refid);
  3528.                     }
  3529.                 }
  3530.             }
  3531.         }
  3532.     }
  3533.  
  3534.     if (   !(flags & JVM_OBJ_MORE_REFERENCES)
  3535.         && (m_HeapInfoNeeded & HMC_INFO_HEAP_OBJECTS))
  3536.     {
  3537.         m_gcinfo.nObjects++;
  3538.  
  3539.         DWORD size;
  3540.         HRESULT hrSize = m_vminfo->GetObjectSize(vmid, &size);
  3541.  
  3542.         if (hrSize == S_OK)
  3543.             m_gcinfo.cbObjects += size;
  3544.             
  3545.         CLASSID cls = NULL;
  3546.  
  3547.         ClassID clsvmid;
  3548.         if (m_vminfo->ObjectInformation(vmid, &clsvmid) == S_OK)
  3549.             cls = LookupClass(clsvmid);
  3550.  
  3551.         if (cls)
  3552.         {
  3553.             cls->liveinstances++;
  3554.             
  3555.             if (hrSize == S_OK)
  3556.             {
  3557.                 cls->livesize += size;
  3558.             }
  3559.             else
  3560.             {
  3561.                 Enter();
  3562.                 {
  3563.                     cls->flags |= CID_FL_INACCURATE;
  3564.                     m_flags |= HMM_FL_INACCURATE;
  3565.                 }
  3566.                 Leave();
  3567.             }
  3568.  
  3569.             if (m_flags & HMM_FL_OBJECT_AGING)
  3570.             {
  3571.                 DWORD age;
  3572.                 if (m_vmheapmon->GetObjectAge(vmid, &age) == S_OK)
  3573.                 {
  3574.                     cls->agesum += age;
  3575.                 }
  3576.                 else
  3577.                 {
  3578.                     Enter();
  3579.                     {
  3580.                         cls->flags |= CID_FL_INACCURATE;
  3581.                         m_flags |= HMM_FL_INACCURATE;
  3582.                     }
  3583.                     Leave();
  3584.                 }
  3585.             }
  3586.         }
  3587.         else
  3588.         {
  3589.             Enter();
  3590.             {
  3591.                 m_flags |= HMM_FL_INACCURATE;
  3592.             }
  3593.             Leave();
  3594.         }
  3595.     }
  3596.  
  3597.     // TODO: allow user to cancel heap dump
  3598.  
  3599.     // We're not concerned with context here, and a flat traversal of the
  3600.     // heap is more efficient for the VM.
  3601.     return S_POSTPONE_REFERENCES;
  3602. }
  3603.  
  3604.  
  3605. //------------------------------------------------------------------------
  3606.  
  3607.  
  3608. HeapMonitorManager::HeapMonitorManager ()
  3609. {
  3610.     m_RefCount = 1;
  3611.  
  3612.     InitializeCriticalSection(&m_cs);
  3613. #ifdef DEBUG
  3614.     m_tidCriticalSectionOwner = INVALID_THREAD_ID;
  3615.     m_CriticalSectionEnterCount = 0;
  3616. #endif // DEBUG
  3617.  
  3618.     m_flags = 0;
  3619.     m_hthd = NULL;
  3620.     m_tid = INVALID_THREAD_ID;
  3621.  
  3622.     m_hinst = NULL;
  3623.     m_hwnd = NULL;
  3624.     m_hmnu = NULL;
  3625.     m_hmnuWindow = NULL;
  3626.     m_mdi = NULL;
  3627.  
  3628.     m_ProgressIndicatorImages = NULL;
  3629.  
  3630.     m_hresumeevt = NULL;
  3631.  
  3632.     m_vminfo = NULL;
  3633.     m_vmheapmon = NULL;
  3634.  
  3635.     m_clients = NULL;
  3636.  
  3637.     m_EventMaskUnion = 0;
  3638.     m_InfoMaskUnion = 0;
  3639.     m_StoppedEventMaskUnion = 0;
  3640.     m_StoppedInfoMaskUnion = 0;
  3641.  
  3642.     m_IDMapChangeCount = 0;
  3643.  
  3644.     m_npkgents = 0;
  3645.     m_pkgents = NULL;
  3646.  
  3647.     m_rgpszContainerDescriptions = NULL;
  3648.     m_rgpszVerboseContainerDescriptions = NULL;
  3649.  
  3650.     m_iGC = 0;
  3651.     ZeroMemory(&m_gcinfo, sizeof(m_gcinfo));
  3652.  
  3653. #ifdef DEBUG
  3654.     m_HeapDumpThreadId = INVALID_THREAD_ID;
  3655. #endif // DEBUG
  3656.  
  3657.     m_trackedobjs = NULL;
  3658.  
  3659.     m_searchcb = NULL;
  3660.  
  3661.     m_heapwalks = NULL;
  3662.  
  3663.     EnterCriticalSection(&s_mgrlistcs);
  3664.     {
  3665.         m_next = s_mgrlist;
  3666.         s_mgrlist = this;
  3667.     }
  3668.     LeaveCriticalSection(&s_mgrlistcs);
  3669.  
  3670.     InterlockedIncrement((LONG*)&g_ModuleRefCount);
  3671. }
  3672.  
  3673.  
  3674. HeapMonitorManager::~HeapMonitorManager ()
  3675. {
  3676.     ASSERT(!m_RefCount);
  3677.  
  3678.     InterlockedDecrement((LONG*)&g_ModuleRefCount);
  3679.  
  3680.     EnterCriticalSection(&s_mgrlistcs);
  3681.     {
  3682.         HeapMonitorManager **prev = &s_mgrlist;
  3683.         while (*prev != this)
  3684.             prev = &(*prev)->m_next;
  3685.         *prev = (*prev)->m_next;
  3686.     }
  3687.     LeaveCriticalSection(&s_mgrlistcs);
  3688.     
  3689.     if (m_flags & HMM_FL_ADDED_TRAY_ICON)
  3690.         RemoveTrayIcon();
  3691.  
  3692.     if (m_searchcb)
  3693.         m_searchcb->Release();
  3694.  
  3695.     TrackedObjectList *trkent = m_trackedobjs;
  3696.     while (trkent)
  3697.     {
  3698.         TrackedObjectList *trash = trkent;
  3699.         trkent = trkent->next;
  3700.         if (trash->tag)
  3701.             delete(trash->tag);
  3702.         delete(trash);
  3703.     }
  3704.  
  3705.     if (m_pkgents)
  3706.     {
  3707.         for (DWORD i = 0; i < m_npkgents; i++)
  3708.         {
  3709.             PkgTokenEntry *ent = &m_pkgents[i];
  3710.             if (!ent->name)
  3711.                 break;
  3712.             delete(ent->name);
  3713.         }
  3714.         delete(m_pkgents);
  3715.     }
  3716.  
  3717.     ClientRecord *clientrec = m_clients;
  3718.     while (clientrec)
  3719.     {
  3720.         ClientRecord *next = clientrec->next;
  3721.         clientrec->client->Release();
  3722.         delete(clientrec);
  3723.         clientrec = next;
  3724.     }
  3725.  
  3726.     if (m_vmheapmon)
  3727.         m_vmheapmon->Release();
  3728.  
  3729.     if (m_vminfo)
  3730.         m_vminfo->Release();
  3731.  
  3732.     if (m_hresumeevt)
  3733.         CloseHandle(m_hresumeevt);
  3734.  
  3735.     if (m_hthd)
  3736.         PostThreadMessage(m_tid, WM_QUIT, 0, 0);
  3737.  
  3738.     if (m_ProgressIndicatorImages)
  3739.         ImageList_Destroy(m_ProgressIndicatorImages);
  3740.  
  3741.     DeletePtrArray((PVOID*)m_rgpszContainerDescriptions, C_LAST - C_FIRST - 1);
  3742.     DeletePtrArray((PVOID*)m_rgpszVerboseContainerDescriptions, C_LAST - C_FIRST - 1);
  3743. }
  3744.  
  3745.  
  3746. BOOL HeapMonitorManager::Initialize (HINSTANCE hInstance)
  3747. {
  3748.     BOOL result;
  3749.  
  3750.     m_hinst = hInstance;
  3751.  
  3752.     result = (m_hresumeevt = CreateEvent(NULL, FALSE, FALSE, NULL)) != NULL;
  3753.  
  3754.     if (result)
  3755.     {
  3756.         result = (m_hthd = CreateThread(NULL, 0, &HeapMonitorManagerMessagePumpThread, this, 0, &m_tid)) != NULL;
  3757.     }
  3758.  
  3759.     return result;
  3760. }
  3761.  
  3762.  
  3763. VOID HeapMonitorManager::OnProcessAttach (HINSTANCE hinst)
  3764. {
  3765.     InitializeCriticalSection(&s_mgrlistcs);
  3766.  
  3767.     s_htrayicon = (HICON)LoadImage(hinst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, 16, 16, 0/*LR_LOADTRANSPARENT*/);
  3768. }
  3769.  
  3770.  
  3771. VOID HeapMonitorManager::OnProcessDetach (HINSTANCE hinst)
  3772. {
  3773.     for (HeapMonitorManager *list = s_mgrlist; list; list = list->m_next)
  3774.     {
  3775.         if (list->m_flags & HMM_FL_ADDED_TRAY_ICON)
  3776.             list->RemoveTrayIconWorker();
  3777.     }
  3778.  
  3779.     DeleteCriticalSection(&s_mgrlistcs);
  3780. }
  3781.  
  3782.  
  3783. //------------------------------------------------------------------------
  3784.  
  3785.  
  3786. PSTR HeapMonitorManager::FetchIDFriendlyName (ID id)
  3787. {
  3788.     PSTR pszname = id->name;
  3789.     if (!pszname && (id->type == ID_PACKAGE || id->type == ID_CLASS))
  3790.     {
  3791.         Enter();
  3792.         {
  3793.             pszname = id->name;
  3794.             if (!pszname)
  3795.             {
  3796.                 PWSTR pwszname = NULL;
  3797.                 BOOL fFreeName = FALSE;
  3798.  
  3799.                 switch (id->type)
  3800.                 {
  3801.                 case ID_PACKAGE:
  3802.                     {
  3803.                         PkgTokenEntry *cur = m_pkgents;
  3804.                         PkgTokenEntry *stop = cur + m_npkgents;
  3805.                         while (cur < stop)
  3806.                         {
  3807.                             if (cur->id == id)
  3808.                             {
  3809.                                 pwszname = cur->name;
  3810.                                 int len = wcslen(pwszname);
  3811.                                 PWCHAR pwch = pwszname+len-1;
  3812.                                 while (*pwch != '.' && *pwch != '/' && pwch > pwszname)
  3813.                                     pwch--;
  3814.                                 if (pwch > pwszname)
  3815.                                     pwch++;
  3816.                                 pwszname = pwch;
  3817.                                 break;
  3818.                             }
  3819.                             cur++;
  3820.                         }
  3821.                     }
  3822.                     break;
  3823.                 
  3824.                 case ID_CLASS:
  3825.                     {
  3826.                         PSTR pclsname;
  3827.                         if (SUCCEEDED(m_vminfo->ClassInformation(id->vmid, &pclsname, NULL, NULL, NULL, NULL)))
  3828.                         {
  3829.                             Utf8ToUnicode(pclsname, &pwszname);
  3830.                             CoTaskMemFree(pclsname);
  3831.                         }
  3832.                     }
  3833.                     break;
  3834.                 }
  3835.             
  3836.                 if (pwszname)
  3837.                 {
  3838.                     UnicodeToANSI(pwszname, -1, &pszname);
  3839.  
  3840.                     id->name = pszname;
  3841.  
  3842.                     if (fFreeName)
  3843.                         delete(pwszname);
  3844.                 }
  3845.             }
  3846.         }
  3847.         Leave();
  3848.     }
  3849.     
  3850.     return pszname;
  3851. }
  3852.  
  3853.  
  3854. //------------------------------------------------------------------------
  3855.  
  3856.  
  3857. ULONG STDMETHODCALLTYPE HeapMonitorManager::AddRef (VOID)
  3858. {
  3859.     ASSERT(m_RefCount && m_RefCount < ULONG_MAX);
  3860.  
  3861.     return InterlockedIncrement((LONG*)&m_RefCount);
  3862. }
  3863.  
  3864.  
  3865. ULONG STDMETHODCALLTYPE HeapMonitorManager::Release (VOID)
  3866. {
  3867.     ASSERT(m_RefCount);
  3868.  
  3869.     ULONG NewRefCount = (ULONG)InterlockedDecrement((LONG*)&m_RefCount);
  3870.     if (NewRefCount)
  3871.         return NewRefCount;
  3872.  
  3873.     delete(this);
  3874.  
  3875.     return 0;
  3876. }
  3877.  
  3878.  
  3879. STDMETHODIMP HeapMonitorManager::QueryInterface (
  3880.         REFIID riid,
  3881.         PVOID *ppvObject)
  3882. {
  3883.     HRESULT hr = S_OK;
  3884.  
  3885.     if (   riid == IID_IUnknown
  3886.         || riid == IID_IJavaEventMonitor
  3887.         || riid == IID_IJavaEventMonitor2)
  3888.     {
  3889.         *ppvObject = (IJavaEventMonitor2*)this;
  3890.     }
  3891.     else if (riid == IID_IHeapInfoCallback)
  3892.     {
  3893.         *ppvObject = (IHeapInfoCallback*)this;
  3894.     }
  3895.     else
  3896.     {
  3897.         *ppvObject = NULL;
  3898.         hr = E_NOINTERFACE;
  3899.     }
  3900.  
  3901.     if (hr == S_OK)
  3902.         AddRef();
  3903.  
  3904.     return(hr);
  3905. }
  3906.  
  3907.  
  3908. //------------------------------------------------------------------------
  3909.  
  3910.  
  3911. IDWrapper::~IDWrapper ()
  3912. {
  3913.     if (name)
  3914.         delete(name);
  3915.     
  3916.     if (type == ID_CLASS)
  3917.     {
  3918.         ClassIDWrapper *cls = (ClassIDWrapper*)this;
  3919.         if (cls->flds)
  3920.             delete(cls->flds);
  3921.     }
  3922.     else if (type == ID_OBJECT)
  3923.     {
  3924.         ASSERT(!(flags & ALL_OID_NONTRANSIENT_FLAGS));
  3925.     }
  3926. }
  3927.  
  3928.