home *** CD-ROM | disk | FTP | other *** search
- // hpmonmgr.cpp
- //
- // Created 10/04/98
- //
- // (C)Copyright 1998-1999 Microsoft Corporation, All rights reserved.
- //
-
- #include "pch.hpp"
- #pragma hdrstop
-
- #include "guids.h"
- #include "hpmonmgr.hpp"
- #include "heapview.hpp"
- #include "clsview.hpp"
- #include "resource.h"
- #include "obsearch.hpp"
- #include "utf8.hpp"
- #include "objlist.hpp"
- #include "gcview.hpp"
-
- // main.cpp
- extern ULONG g_ModuleRefCount;
-
-
- //
- // ------------------------------------------------------------------------
- // Synchronization
- //
- // - profiler events may be received from the VM on any thread. This thread
- // may be one of our ui threads if a VM api called from the ui thread
- // generates an event.
- // - some ui elements will contain IDWrappers as lParams. Use of these IDs on
- // the ui thread needs to be serialized with their destruction on some other
- // thread.
- // - when a client window is destroyed, its IHeapMonitorClient needs to be
- // revoked. Dispatch of messages from random event threads needs to be
- // serialized with removing the client from the list.
- //
- // A UniqueID from the VM becomes invalid upon returning from the event
- // callback notifying the monitor that the ID is becoming invalid. UI threads
- // may already be making use of the ID, so the monitor must stall the event
- // thread until the UI thread has completed all uses of the ID. This means
- // that communication between event threads and ui threads must be synchronous
- // (use SendMessage). Further, because events may be generated on ui threads
- // while events are being handled on other threads, no locks needed by event
- // handling may be held across the SendMessage. The VM does not hold locks
- // across event dispatch that may be needed on other threads to service an
- // IJavaEventMonitorIDInfo[n] call. Use of IDs on the UI thread needs to be
- // serialized with use on non-UI threads - while on the UI thread, it is safe
- // to hold a lock around messaging since it will be serviced on the same
- // thread.
- //
- // Note that the VM ensures that it is not possible for an event to be received
- // that refers to an ID for which a creation event is simultaneously being
- // sent. The second event will not be dispatched until the event callback for
- // the first event has returned. This form of out-of-order event processing is
- // not possible. For the purposes of this sample, creation events are handled
- // synchronously, just like destruction events, so that it is impossible to
- // handle a destruction event before a creation event.
- //
- // Note that although out-of-order events are not possible, IDs may be
- // discovered for which creation events have not been received. Class
- // load/unload events are not fully implemented for all class types in the
- // current VM.
- //
- // Also, due to a bug in the VM, thread destruction event reporting is not
- // serialized with heap dumping. The VM may report thread containers for
- // threads that have not yet been reported to the monitor or have just been
- // destroyed, and thread destruction events may be sent on another thread while
- // a heap dump is in progress. (Since gc is using the thread, obviously the
- // thread can't really be destroyed, and in fact it really isn't. Only the
- // reporting of this event is messed up. Sorry.) This is the one exception
- // where an id can be used beyond its destruction event: if the destruction
- // event for a thread id is received while a heap dump is in progress, the
- // thread id may be safely used until returning from the C_END notification.
- //
- // Another oddity: a IHeapInfoCallback cannot be revoked asynchronously. It
- // must be revoked during a heap dump, or during a JVM_EVENT_TYPE_GC_STARTED
- // or JVM_EVENT_TYPE_GC_FINISHED event.
- //
- // Synchronization with window closing is handled by BasicClient::WndProc.
- //
- //
- // ------------------------------------------------------------------------
- // Heap exploration
- //
- // HeapMonitorManager performs a "flat" traversal of the heap. The VM reports
- // all roots first, and by returning S_POSTPONE_REFERENCES for each root, all
- // objects will be visitied within the C_HEAP container. This provides clients
- // with a quick view of what is to come.
- //
- // Once all roots and their references are known, the heap may be explored
- // manually using IJavaEventMonitorIDInfo2::GetObjectField and
- // IJavaEventMonitorIDInfo2::GetArrayElement. Manual exploration requires
- // hashing all objects to know when an object has been re-discovered (to
- // identify cycles and objects with multiple references). The VM specifies
- // which objects have already been reported - this alone (see exception below)
- // indicates objects with multiple references, so only these objects need to
- // be hashed. Typically these objects are a small percentage of total number
- // of objects, substantially reducing the amount of storage needed to safely
- // navigate the heap.
- //
- // Heap exploration may take a long time, so clients may simultaneously explore
- // objects manually. Any objects discovered in this manner must be hashed.
- // Since clients must follow objects starting from roots, if they run into a
- // cycle, they will necessarily have caused all of the nodes in the cycle to be
- // hashed. Once heap enumeration is complete, all objects with multiple
- // references are known, so no further hashing is required.
- //
- // For exploration that may touch the entire heap, clients should wait until
- // enumeration completes, then request the heap dump thread to call
- // IJavaHeapMonitor2::WalkHeap (ex. see HeapMonitorManager::SearchHeap, which
- // is used by ClassInstancesViewer and ObjectReferencesViewer).
- //
- // IJavaEventMonitorIDInfo2::GetObjectField and
- // IJavaEventMonitorIDInfo2::GetArrayElement are used for manual exploration.
- // In VM builds older than 3223, these apis had some bugs:
- // - with object aging enabled, GetObjectField might return invalid fields of
- // some variable size classes
- // - with object aging enabled, GetArrayElement might return an invalid
- // element past the end of the array
- // - for arrays of objects, GetArrayElement might return an invalid element
- // past the end of the array
- // To work around these bugs, during heap dumping, record the actual number of
- // references for instances of variable-size classes and for arrays of
- // objects, and use this to limit the number of reference fields or elements
- // retrieved from the object. This sample does not demonstrate this.
- //
- //
- // ------------------------------------------------------------------------
- // Detecting cycles
- //
- // The JVM_OBJ_ALREADY_REPORTED flag indicates an object with multiple
- // references, which indicates a potential cycle. If S_OK is always returned
- // from both ObjectReferences and RootReferences, then a depth-first traversal
- // is performed and this bit is always accurate. A reference will be reported
- // for an object before the object is visited, i.e. JVM_OBJ_ALREADY_VISITED
- // will never be set for an object without JVM_OBJ_ALREADY_REPORTED also set.
- //
- // If S_POSTPONE_REFERENCES is ever returned, then if an object is visited
- // before any of its references, JVM_OBJ_ALREADY_REPORTED will be set for the
- // first reference. This is because the VM considers visiting an act of
- // reporting, so that self-referencing objects can be detected.
- //
- // There are two ways to deal with this:
- //
- // 1. always return S_OK. However, always returning S_POSTPONE_REFERENCES is a
- // slightly faster way to simply find all objects.
- //
- // 2. detect when an object is visited but not yet reported. This means both
- // JVM_OBJ_ALREADY_VISITED and JVM_OBJ_ALREADY_REPORTED will be clear for the
- // object in ObjectReferences. Hash the object and remember this condition.
- // When the first reference to this object is discovered, via RootReferences or
- // ObjectReferences, pretend the JVM_OBJ_ALREADY_REPORTED flag is clear. For
- // subsequent references, JVM_OBJ_ALREADY_REPORTED will always be correctly set.
- //
- // Example:
- //
- // Reference order: root -> A -> B -> A
- // C_HEAP reporting order: B, A
- //
- // In S_OK-always mode, nodes are traversed in reference order:
- //
- // 1. root refers to A (!VISITED && !REPORTED). A is marked REPORTED.
- // 2. A (!VISITED && REPORTED) refers to B (!VISITED && !REPORTED). A is marked VISITED. B is marked REPORTED.
- // 3. B (!VISITED && REPORTED) refers to A (VISITED && REPORTED). B is marked VISITED.
- //
- // In S_POSTPONE_REFERENCES-always mode, nodes are reported in the C_HEAP
- // container in arbitrary order, with all roots reported first:
- //
- // 1. root refers to A (!VISITED && !REPORTED). A is marked REPORTED.
- // 2. B (!VISITED && !REPORTED) refers to A (!VISITED && REPORTED). B is marked VISITED and REPORTED.
- // =========
- // 3. A (!VISITED && REPORTED) refers to B (VISITED && REPORTED). A is marked VISITED.
- // ========
- //
-
-
- //static
- CRITICAL_SECTION HeapMonitorManager::s_mgrlistcs;
- //static
- HeapMonitorManager *HeapMonitorManager::s_mgrlist = NULL;
- //static
- HICON HeapMonitorManager::s_htrayicon;
-
-
- //------------------------------------------------------------------------
-
-
- BOOL HeapMonitorManager::RegisterClient (IHeapMonitorClient *newclient, HeapMonitorClientRegistrationInfo *pinfo)
- {
- ASSERT(!(pinfo->StoppedEventMask & HMC_NON_GC_EVENTS));
-
- BOOL ret;
-
- ClientRecord *rec = new(ClientRecord());
- ret = (rec != NULL);
- if (ret)
- {
- Enter();
- {
- rec->next = m_clients;
- m_clients = rec;
-
- (rec->client = newclient)->AddRef();
- rec->refcount = 1;
-
- rec->EventMask = pinfo->EventMask | HMC_UNMASKABLE_EVENTS;
- rec->InfoMask = pinfo->InfoMask | GetInfoNeededForEvents(pinfo->EventMask);
-
- m_EventMaskUnion |= rec->EventMask;
- m_InfoMaskUnion |= rec->InfoMask;
-
- rec->StoppedEventMask = pinfo->StoppedEventMask | HMC_UNMASKABLE_EVENTS;
- rec->StoppedInfoMask = pinfo->StoppedInfoMask | GetInfoNeededForEvents(pinfo->StoppedEventMask);
-
- m_StoppedEventMaskUnion |= rec->StoppedEventMask;
- m_StoppedInfoMaskUnion |= rec->StoppedInfoMask;
- }
- Leave();
- }
-
- // Clients don't get events for already-existing ids. Presumably they
- // can catch up in a more efficient manner by fetching them all in a
- // clump...this entire process needs to be atomic.
-
- return ret;
- }
-
-
- VOID HeapMonitorManager::UnregisterClient (IHeapMonitorClient *deadclient)
- {
- Enter();
- {
- DWORD NewEventMaskUnion = 0;
- DWORD NewInfoMaskUnion = 0;
- DWORD NewStoppedEventMaskUnion = 0;
- DWORD NewStoppedInfoMaskUnion = 0;
- #ifdef DEBUG
- BOOL fFound = FALSE;
- #endif // DEBUG
-
- ClientRecord **prev = &m_clients;
- for (;;)
- {
- ClientRecord *cur = *prev;
- if (cur != NULL)
- {
- if (cur->client == deadclient)
- {
- #ifdef DEBUG
- ASSERT(!fFound);
- fFound = TRUE;
- #endif // DEBUG
-
- deadclient->Release();
- if ((--cur->refcount) == 0)
- {
- *prev = cur->next;
- delete(cur);
- continue;
- }
- }
-
- NewEventMaskUnion |= cur->EventMask;
- NewInfoMaskUnion |= cur->InfoMask;
- NewStoppedEventMaskUnion |= cur->StoppedEventMask;
- NewStoppedInfoMaskUnion |= cur->StoppedInfoMask;
-
- prev = &cur->next;
- }
- else
- {
- break;
- }
- }
-
- ASSERT(fFound);
-
- m_EventMaskUnion = NewEventMaskUnion;
- m_InfoMaskUnion = NewInfoMaskUnion;
- m_StoppedEventMaskUnion = NewStoppedEventMaskUnion;
- m_StoppedInfoMaskUnion = NewStoppedInfoMaskUnion;
- }
- Leave();
- }
-
-
- VOID HeapMonitorManager::IterateClients (DWORD mask, CLIENTITERFN *cb, PVOID token)
- {
- ASSERT(!Entered());
-
- // Bump the refcount of the record of each client we will notify. If
- // new clients appear while we're sending notifications, we need to
- // take care not to adjust their refcounts. New clients are added at
- // the head of the list, so we addref everything from the current head,
- // remember the current head, and release everything from the saved
- // head.
-
- ClientRecord *first;
- ClientRecord *cur;
-
- Enter();
- {
- first = m_clients;
- if (!first)
- {
- bail:
- Leave();
- return;
- }
-
- if (!IsEventRequested(mask))
- {
- goto bail;
- }
-
- cur = first;
- do
- {
- cur->refcount++;
- cur->client->AddRef();
-
- cur = cur->next;
- }
- while (cur != NULL);
- }
- Leave();
-
- cur = first;
- do
- {
- if ( (cur->EventMask & mask)
- || (m_flags & HMM_FL_STOPPED) && (cur->StoppedEventMask & mask))
- {
- (*cb)(cur->client, token);
- }
-
- cur = cur->next;
- }
- while (cur != NULL);
-
- Enter();
- {
- ClientRecord **pprev = &first;
- for (;;)
- {
- cur = *pprev;
- if (cur != NULL)
- {
- cur->client->Release();
- if ((--cur->refcount) > 0)
- {
- pprev = &cur->next;
- }
- else
- {
- // Rare case: a client was removed while we were
- // notifying it. If it was the first client we
- // notified, re-check the head list to see if any new
- // clients were added. If so, find the one linked to
- // the removed client.
-
- if (pprev == &first)
- {
- if (first == m_clients)
- {
- pprev = &m_clients;
- }
- else
- {
- ClientRecord *prev = m_clients;
- for (;;)
- {
- ClientRecord *next = prev->next;
- if (next == cur)
- break;
- prev = next;
- }
- pprev = &prev->next;
- }
- }
-
- *pprev = cur->next;
- delete(cur);
- }
- }
- else
- {
- break;
- }
- }
- }
- Leave();
- }
-
-
- //------------------------------------------------------------------------
-
-
- //static
- DWORD WINAPI HeapMonitorManager::HeapMonitorManagerMessagePumpThread (PVOID token)
- {
- HeapMonitorManager *hmm = (HeapMonitorManager*)token;
-
- if (hmm->InitializeUI())
- {
- MSG msg;
- while (GetMessage(&msg, (HWND) NULL, 0, 0))
- {
- // Don't have any accelerators.
- //if ( !TranslateMDISysAccel(m_mdi, &msg)
- // && !TranslateAccelerator(m_hwnd, m_accel, &msg))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- }
-
- return 0;
- }
-
-
- BOOL HeapMonitorManager::InitializeUI ()
- {
- BOOL result;
-
- InitCommonControls();
-
- result = (m_hmnu = LoadMenu(m_hinst, MAKEINTRESOURCE(IDR_MAINMENU))) != NULL;
-
- if (result)
- {
- result = (m_hmnuWindow = GetSubMenu(m_hmnu, 1)) != NULL;
- }
-
- HICON hmainicon = NULL;
- if (result)
- {
- result = (hmainicon = LoadIcon(m_hinst, MAKEINTRESOURCE(IDI_MAINICON))) != NULL;
- }
-
- if (result)
- {
- result = (m_ProgressIndicatorImages = ImageList_LoadImage(
- m_hinst,
- MAKEINTRESOURCE(IDB_HEAPDUMP_PROGRESS),
- 16,
- 0,
- CLR_DEFAULT,
- IMAGE_BITMAP,
- LR_LOADTRANSPARENT)) != NULL;
- }
-
- if (result)
- {
- WNDCLASS wc;
- ZeroMemory(&wc, sizeof(wc));
- wc.lpfnWndProc = &WndProc;
- wc.hInstance = m_hinst;
- wc.hIcon = hmainicon;
- wc.lpszClassName = WC_HEAPMONITOR;
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- result = RegisterClass(&wc);
- }
-
- if (result)
- {
- result = CreateWindowEx(
- 0,
- WC_HEAPMONITOR ,
- "Java Heap Monitor",
- WS_OVERLAPPEDWINDOW | WS_MINIMIZE,
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- NULL,
- m_hmnu,
- m_hinst,
- this) != NULL;
- }
-
- if (result)
- {
- ShowWindow(m_hwnd, SW_HIDE);
-
- result = AddTrayIcon();
- }
-
- return result;
- }
-
-
- VOID HeapMonitorManager::DestroyNow ()
- {
- ASSERT(m_flags & HMM_FL_CLOSED);
-
- Enter();
- {
- if (!(m_flags & HMM_FL_DESTRUCTION_PENDING))
- {
- // No more events, please.
- m_vminfo->SetEventMask(0);
-
- // No more heap dumps, please.
- m_vmheapmon->GetHeapInfo(NULL);
-
- SendNotifyMessage(m_hwnd, HMM_WM_DESTROY_NOW, 0, 0);
-
- m_flags |= HMM_FL_DESTRUCTION_PENDING;
- }
- }
- Leave();
- }
-
-
- VOID HeapMonitorManager::RedrawMenuBar ()
- {
- RedrawWindow(m_hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
- }
-
-
- BOOL HeapMonitorManager::GrayMenu (UINT idm)
- {
- ASSERT(CanSendUIMessages());
-
- BOOL result;
-
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_STATE;
- mii.fState = MFS_GRAYED;
-
- result = SetMenuItemInfo(m_hmnu, idm, FALSE, &mii);
- if (result)
- RedrawMenuBar();
-
- return result;
- }
-
-
- BOOL HeapMonitorManager::ChangeMenuTextAndUngray (UINT idm, PCSTR text)
- {
- ASSERT(CanSendUIMessages());
-
- BOOL result;
-
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_STATE | MIIM_TYPE;
- mii.fType = MFT_STRING;
- mii.dwTypeData = (PSTR)text;
- mii.cch = strlen(text);
- mii.fState = 0;
-
- result = SetMenuItemInfo(m_hmnu, idm, FALSE, &mii);
- if (result)
- RedrawMenuBar();
-
- return result;
- }
-
-
- // Called in response to selecting the 'Go' or 'Stop' menu.
- VOID HeapMonitorManager::StopOrGo ()
- {
- Enter();
- {
- if (!(m_flags & (HMM_FL_STOP | HMM_FL_STOPPED)))
- {
- // Gray the "Stop!" item, and request a heap dump.
-
- if (GrayMenu(IDM_STOPGO))
- {
- m_flags |= HMM_FL_STOP;
- }
- }
- else if (m_flags & HMM_FL_STOPPED)
- {
- // Gray the "Go!" item, and resume VM execution.
-
- if (GrayMenu(IDM_STOPGO))
- {
- m_flags |= HMM_FL_GO;
-
- SetEvent(m_hresumeevt);
- }
- }
- }
- Leave();
- }
-
-
- VOID HeapMonitorManager::IndicateStopped ()
- {
- ASSERT(m_flags & HMM_FL_STOPPED);
-
- // Un-gray the "Stop!" item, and change its text to "Go!".
-
- ChangeMenuTextAndUngray(IDM_STOPGO, "Go!");
- }
-
- VOID HeapMonitorManager::IndicateRunning ()
- {
- ASSERT(!(m_flags & (HMM_FL_STOP | HMM_FL_STOPPED)));
-
- // Un-gray the "Go!" item, and change its text to "Stop!".
-
- ChangeMenuTextAndUngray(IDM_STOPGO, "Stop!");
- }
-
-
- // static
- VOID CALLBACK HeapMonitorManager::UpdateProgressIndicator(
- HWND hwnd, // handle to window
- UINT uMsg, // WM_TIMER message
- UINT idEvent, // timer identifier
- DWORD dwTime // current system time
- )
- {
- HeapMonitorManager *hmm = (HeapMonitorManager*)GetWindowLong(hwnd, GWL_USERDATA);
-
- if ( hmm->m_ProgressIndicator != hmm->m_LastProgressIndicator
- || hmm->m_gcinfo.nObjects != hmm->m_LastObjectCount)
- {
- hmm->m_LastProgressIndicator = hmm->m_ProgressIndicator;
- hmm->m_LastObjectCount = hmm->m_gcinfo.nObjects;
-
- hmm->m_iProgressIndicatorImage = (hmm->m_iProgressIndicatorImage + 1) % 9;
-
- RedrawWindow(hmm->m_status, NULL, NULL, RDW_INVALIDATE);
- }
- }
-
-
- BOOL HeapMonitorManager::StartHeapDumpProgressIndicatorWorker ()
- {
- BOOL fSuccess = FALSE;
-
- Enter();
- {
- ASSERT(!(m_flags & HMM_FL_PROGRESS_INDICATOR));
-
- INT rgPartRightEdges[2] = { 16, -1 };
- if (SendMessage(m_status, SB_SETPARTS, ARRAY_ELEMENTS(rgPartRightEdges), (LPARAM)&rgPartRightEdges[0]))
- {
- if (SendMessage(m_status, SB_SETTEXT, SBT_OWNERDRAW, 0))
- {
- m_ProgressIndicatorTimer = SetTimer(m_hwnd, 0, 500, (TIMERPROC)&UpdateProgressIndicator);
-
- if (m_ProgressIndicatorTimer)
- {
- m_ProgressIndicator = 0;
-
- m_LastProgressIndicator = 0;
- m_LastObjectCount = 0;
-
- m_iProgressIndicatorImage = 0;
-
- m_flags |= HMM_FL_PROGRESS_INDICATOR;
-
- fSuccess = TRUE;
- }
- }
- }
-
- if (!fSuccess)
- {
- rgPartRightEdges[0] = -1;
- SendMessage(m_status, SB_SETPARTS, 1, (LPARAM)&rgPartRightEdges[0]);
-
- SendMessage(m_status, SB_SETTEXT, 0, (LPARAM)"");
- }
- }
- Leave();
-
- return fSuccess;
- }
-
-
- VOID HeapMonitorManager::StopHeapDumpProgressIndicatorWorker ()
- {
- if (m_flags & HMM_FL_PROGRESS_INDICATOR)
- {
- Enter();
- {
- KillTimer(m_hwnd, 0);
- m_ProgressIndicatorTimer = 0;
-
- m_flags -= HMM_FL_PROGRESS_INDICATOR;
-
- INT rgPartRightEdges[1] = { -1 };
- SendMessage(m_status, SB_SETPARTS, 1, (LPARAM)&rgPartRightEdges[0]);
-
- SendMessage(m_status, SB_SETTEXT, 0, (LPARAM)"");
- }
- Leave();
- }
- }
-
-
- BOOL HeapMonitorManager::StartHeapDumpProgressIndicator ()
- {
- ASSERT(CanSendUIMessages());
- ASSERT(OnHeapDumpThread());
-
- return SendMessage(m_hwnd, HMM_WM_START_PROGRESS_INDICATOR, 0, 0) != FALSE;
- }
-
-
- VOID HeapMonitorManager::StopHeapDumpProgressIndicator ()
- {
- ASSERT(CanSendUIMessages());
- ASSERT(OnHeapDumpThread());
-
- SendMessage(m_hwnd, HMM_WM_STOP_PROGRESS_INDICATOR, 0, 0);
- }
-
-
- VOID HeapMonitorManager::SetStatusText (PCSTR text)
- {
- ASSERT(CanSendUIMessages());
-
- if (m_flags & HMM_FL_PROGRESS_INDICATOR)
- {
- SendMessage(m_status, SB_SETTEXT, 1, (LPARAM)text);
- }
- else
- {
- SetWindowText(m_status, text);
- }
- }
-
-
- BOOL HeapMonitorManager::AddTrayIcon ()
- {
- ASSERT(!(m_flags & HMM_FL_ADDED_TRAY_ICON));
-
- BOOL ret;
-
- NOTIFYICONDATA nid;
-
- nid.cbSize = sizeof(nid);
- ZeroMemory(&nid, sizeof(nid));
-
- nid.hWnd = m_hwnd;
- nid.uFlags = (NIF_ICON | NIF_MESSAGE | NIF_TIP);
- nid.uCallbackMessage = HMM_WM_ACTIVATE;
- nid.hIcon = s_htrayicon;
- CopyMemory(nid.szTip, "Java Heap Monitor", 18);
-
- ret = Shell_NotifyIcon(NIM_ADD, &nid);
-
- if (ret)
- {
- // Use critical section just to make flags modification atomic.
- Enter();
- {
- ASSERT(!(m_flags & HMM_FL_ADDED_TRAY_ICON));
- m_flags |= HMM_FL_ADDED_TRAY_ICON;
- }
- Leave();
- }
-
- return ret;
- }
-
-
- BOOL HeapMonitorManager::RemoveTrayIconWorker ()
- {
- NOTIFYICONDATA nid;
-
- nid.cbSize = sizeof(nid);
- ZeroMemory(&nid, sizeof(nid));
-
- nid.hWnd = m_hwnd;
-
- return Shell_NotifyIcon(NIM_DELETE, &nid);
- }
-
-
- BOOL HeapMonitorManager::RemoveTrayIcon ()
- {
- ASSERT(m_flags & HMM_FL_ADDED_TRAY_ICON);
-
- BOOL ret = RemoveTrayIconWorker();
-
- if (ret)
- {
- // Use critical section just to make flags modification atomic.
- Enter();
- {
- ASSERT(m_flags & HMM_FL_ADDED_TRAY_ICON);
- m_flags -= HMM_FL_ADDED_TRAY_ICON;
- }
- Leave();
- }
-
- return ret;
- }
-
-
- VOID HeapMonitorManager::OnCreateWindow (HWND wnd, LPCREATESTRUCT pcs)
- {
- BOOL result;
-
- m_hwnd = wnd;
-
- result = (m_status = CreateStatusWindow(
- WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
- "",
- wnd,
- IDC_STATUS)) != NULL;
-
- if (result)
- {
- // Minimum size of the progress indicator bitmaps.
- SendMessage(m_status, SB_SETMINHEIGHT, 16, 0);
-
- CLIENTCREATESTRUCT ccs;
-
- ccs.hWindowMenu = m_hmnuWindow;
- ccs.idFirstChild = IDM_WINDOW_FIRSTCHILD;
-
- result = (m_mdi = CreateWindow(
- "MDICLIENT",
- NULL,
- WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
- 0, 0, 0, 0,
- wnd,
- NULL,
- m_hinst,
- &ccs)) != NULL;
- }
-
- if (result)
- {
- ShowWindow(m_mdi, SW_SHOW);
- }
- }
-
-
- VOID HeapMonitorManager::CreateNewHeapViewer ()
- {
- HeapViewer *hv = new(HeapViewer());
- if (hv)
- {
- hv->Initialize(this);
-
- hv->Release();
- }
- }
-
-
- VOID HeapMonitorManager::CreateNewClassViewer ()
- {
- ClassListViewer *clv = new(ClassListViewer());
- if (clv)
- {
- clv->Initialize(this);
-
- clv->Release();
- }
- }
-
-
- VOID HeapMonitorManager::CreateNewGCHistoryViewer ()
- {
- GCHistoryViewer *gchv = new(GCHistoryViewer());
- if (gchv)
- {
- gchv->Initialize(this);
-
- gchv->Release();
- }
- }
-
-
- VOID HeapMonitorManager::CreateNewTrackedObjectListViewer ()
- {
- ObjectListViewer *olv = new(ObjectListViewer());
- if (olv)
- {
- olv->Initialize(this, "Tracked Objects", OID_FL_TRACKED);
-
- olv->Release();
- }
- }
-
-
- VOID HeapMonitorManager::CreateNewTaggedObjectListViewer ()
- {
- ObjectListViewer *olv = new(ObjectListViewer());
- if (olv)
- {
- olv->Initialize(this, "Tagged Objects", OID_FL_TAGGED);
-
- olv->Release();
- }
- }
-
-
- //static
- LRESULT CALLBACK HeapMonitorManager::WndProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- HeapMonitorManager *hmm = (HeapMonitorManager*)GetWindowLong(wnd, GWL_USERDATA);
-
- switch (msg)
- {
- case WM_CREATE:
- {
- hmm = (HeapMonitorManager*)((CREATESTRUCT*)lParam)->lpCreateParams;
-
- SetWindowLong(wnd, GWL_USERDATA, (LONG)hmm);
- hmm->AddRef();
-
- hmm->OnCreateWindow(wnd, (LPCREATESTRUCT)lParam);
- }
- return 0;
-
- case WM_COMMAND:
- {
- //WORD wNotifyCode = HIWORD(wParam); // notification code
- WORD wID = LOWORD(wParam); // item, control, or accelerator identifier
- //HWND hwndCtl = (HWND) lParam; // handle of control
- switch (wID)
- {
- case IDM_STOPGO:
- hmm->StopOrGo();
- return 0;
-
- case IDM_WINDOW_NEWHEAPVIEWER:
- hmm->CreateNewHeapViewer();
- break;
-
- case IDM_WINDOW_NEWCLASSVIEWER:
- hmm->CreateNewClassViewer();
- break;
-
- case IDM_WINDOW_NEWGCSTATSVIEWER:
- hmm->CreateNewGCHistoryViewer();
- break;
-
- case IDM_WINDOW_NEWTRKOBJVIEWER:
- hmm->CreateNewTrackedObjectListViewer();
- break;
-
- case IDM_WINDOW_NEWTAGOBJVIEWER:
- hmm->CreateNewTaggedObjectListViewer();
- break;
- }
- }
- break;
-
- case WM_CLOSE:
-
- BOOL fCanCloseNow;
- fCanCloseNow = TRUE;
-
- hmm->Enter();
- {
- hmm->m_flags |= HMM_FL_CLOSED;
-
- hmm->GrayMenu(IDM_STOPGO);
-
- DWORD EventMask;
- if (hmm->m_vminfo->GetEventMask(&EventMask) == S_OK)
- hmm->m_vminfo->SetEventMask(EventMask | JVM_MONITOR_GARBAGE_COLLECTIONS);
-
- if (hmm->m_flags & HMM_FL_STOPPED)
- {
- fCanCloseNow = FALSE;
-
- hmm->m_flags |= HMM_FL_GO;
-
- SetEvent(hmm->m_hresumeevt);
- }
- }
- hmm->Leave();
-
- if (hmm->m_flags & HMM_FL_ADDED_TRAY_ICON)
- hmm->RemoveTrayIcon();
-
- ShowWindow(wnd, SW_HIDE);
-
- hmm->SendClosingEvent();
-
- return 0;
-
- case HMM_WM_DESTROY_NOW:
-
- DestroyWindow(wnd);
-
- return 0;
-
- case WM_DESTROY:
-
- SetWindowLong(wnd, GWL_USERDATA, (LONG)NULL);
- hmm->Release();
-
- break;
-
- case WM_SIZE:
- {
- LONG w = LOWORD(lParam);
- LONG h = HIWORD(lParam);
-
- RECT rc;
- GetClientRect(hmm->m_status, &rc);
- LONG statush = rc.bottom - rc.top;
- MoveWindow(hmm->m_status, 0, h-statush, w, h, TRUE);
- h -= statush;
-
- MoveWindow(hmm->m_mdi, 0, 0, w, h, TRUE);
- }
- return 0;
-
- case WM_SYSCOMMAND:
- if (wParam == SC_MINIMIZE)
- {
- ShowWindow(wnd, SW_MINIMIZE);
- ShowWindow(wnd, SW_HIDE);
- hmm->AddTrayIcon();
- return 0;
- }
- break;
-
- case HMM_WM_ACTIVATE:
- if (lParam == WM_LBUTTONUP)
- {
- hmm->RemoveTrayIcon();
- ShowWindow(wnd, SW_SHOW);
- ShowWindow(wnd, SW_RESTORE);
- }
- return 0;
-
- case HMM_WM_START_PROGRESS_INDICATOR:
- return hmm->StartHeapDumpProgressIndicatorWorker();
-
- case HMM_WM_STOP_PROGRESS_INDICATOR:
- hmm->StopHeapDumpProgressIndicatorWorker();
- return 0;
-
- case WM_DRAWITEM:
- DRAWITEMSTRUCT *pdis;
- pdis = (DRAWITEMSTRUCT*)lParam;
- if (ImageList_Draw(hmm->m_ProgressIndicatorImages, hmm->m_iProgressIndicatorImage, pdis->hDC, 0, 0, ILD_NORMAL))
- return 0;
- return 0;
-
- // REMIND: WM_COMMAND, WM_MENUCHAR, and WM_SETFOCUS need to be passed to
- // mdi proc
- }
-
- if (hmm)
- {
- HWND hmdi = hmm->m_mdi;
- if (hmdi)
- return DefFrameProc(wnd, hmdi, msg, wParam, lParam);
- }
-
- return DefWindowProc(wnd, msg, wParam, lParam);
- }
-
-
- //------------------------------------------------------------------------
-
-
- PKGID HeapMonitorManager::LookupPackage (PKGID parentpkgid, PCWSTR pcszPackageName)
- {
- PKGID pkgid = NULL;
-
- PkgTokenEntry *pkgent = GetPackageEntry(pcszPackageName);
- if (pkgent)
- {
- if (pkgent->id)
- {
- pkgid = pkgent->id;
- }
- else
- {
- pkgid = new(PackageIDWrapper());
- if (pkgid)
- {
- pkgent->id = pkgid;
- pkgid->vmid = (UniqueID)pkgent;
- pkgid->parent = parentpkgid;
-
- Leave();
- {
- SendPackageCreatedEvent(pkgid);
- }
- Enter();
- }
- }
- }
-
- return pkgid;
- }
-
-
- CLASSID HeapMonitorManager::LookupClass (ClassID vmid)
- {
- CLASSID cls = (CLASSID)LookupID(vmid);
- if (!cls)
- cls = ClassLoaded(vmid);
-
- return cls;
- }
-
-
- OBJID HeapMonitorManager::LookupObject (ObjectID vmid)
- {
- OBJID id;
- Enter();
- {
- id = (OBJID)LookupID(vmid);
- if (id == NULL)
- id = CreateOBJID(vmid);
- }
- Leave();
- return id;
- }
-
-
- THREADID HeapMonitorManager::LookupThread (ThreadID vmid)
- {
- THREADID thd = (THREADID)LookupID(vmid);
- if (!thd)
- thd = ThreadCreated(vmid, TRUE);
- return thd;
- }
-
-
- int HeapMonitorManager::IterateIDs (IDITERFN *cb, PVOID cbtoken)
- {
- // Not necessary, but no sense in entering the lock twice when the
- // caller can just use IterateIDs_Safe.
- ASSERT(!Entered());
-
- int ret;
-
- Enter();
- {
- ret = IterateIDs_Safe(cb, cbtoken);
- }
- Leave();
-
- return ret;
- }
-
-
- //static
- int HeapMonitorManager::DeleteTransientIDs (PCVOID key, PVOID value, PVOID token)
- {
- ID id = (ID)value;
-
- int result = 1;
-
- switch (id->type)
- {
- case ID_OBJECT:
- {
- OBJID obj = (OBJID)id;
- if (!(obj->flags & ALL_OID_NONTRANSIENT_FLAGS))
- {
- delete(obj);
- result = 0;
- }
- else
- {
- obj->flags &= ~ALL_OID_TRANSIENT_FLAGS;
- }
- }
- break;
-
- case ID_STACKFRAME:
- case ID_ROOT:
- case ID_GHOST_THREAD:
- delete(id);
- result = 0;
- break;
-
- case ID_THREAD:
- THREADID thd = (THREADID)id;
- if (!(thd->flags & TID_FL_DEAD))
- {
- thd->curframe = NULL;
- }
- else
- {
- delete(thd);
- result = 0;
- }
- break;
- }
-
- return result;
- }
-
-
- //static
- int HeapMonitorManager::ResetPerGCIDInfo (PCVOID key, PVOID val, PVOID token)
- {
- ASSERT(((HeapMonitorManager*)token)->Entered());
-
- ID id = (ID)val;
-
- DWORD oldflags = id->flags;
- DWORD newflags = oldflags;
-
- newflags &= ~ALL_ID_PER_GC_FLAGS;
-
- switch (id->type)
- {
- case ID_CLASS:
- {
- CLASSID cls = (CLASSID)id;
- cls->liveinstances = 0;
- cls->livesize = 0;
- cls->agesum = 0;
- newflags &= ~ALL_CID_PER_GC_FLAGS;
- }
- break;
- }
-
- if (oldflags != newflags)
- id->flags = newflags;
-
- // REMIND: if you return 0, need to bump the change count
- return 1;
- }
-
-
- HeapMonitorManager::PkgTokenEntry *HeapMonitorManager::GetPackageEntry (PCWSTR pkgname)
- {
- ASSERT(Entered());
-
- PkgTokenEntry *ent = NULL;
- int namelen = wcslen(pkgname);
- int namesize = (namelen+1)*sizeof(*pkgname);
-
- // TODO: hash using pooled strings?
-
- if (m_pkgents != NULL)
- {
- ent = &m_pkgents[0];
-
- for (;;)
- {
- if (ent->name == NULL)
- break;
-
- if (memcmp(pkgname, ent->name, namesize) == 0)
- break;
-
- ent++;
- if (ent == m_pkgents+m_npkgents)
- {
- DWORD newcount = m_npkgents*2;
- PkgTokenEntry *newpkgents = new(PkgTokenEntry[newcount]);
- if (newpkgents != NULL)
- {
- CopyMemory(newpkgents, m_pkgents, m_npkgents*sizeof(*m_pkgents));
- ZeroMemory(newpkgents+m_npkgents, m_npkgents*sizeof(*m_pkgents));
- m_pkgents = newpkgents;
- ent = newpkgents+m_npkgents;
- m_npkgents = newcount;
- }
- else
- {
- ent = NULL;
- }
-
- break;
- }
- }
- }
- else
- {
- m_npkgents = 10;
- m_pkgents = new(PkgTokenEntry[m_npkgents]);
- if (m_pkgents != NULL)
- {
- ZeroMemory(m_pkgents, m_npkgents*sizeof(*m_pkgents));
- ent = &m_pkgents[0];
- }
- else
- {
- ent = NULL;
- }
- }
-
- if (ent != NULL && ent->name == NULL)
- {
- if ((ent->name = new(WCHAR[namelen+1])) != NULL)
- CopyMemory(ent->name, pkgname, namesize);
- else
- ent = NULL;
- }
-
- return ent;
- }
-
-
- BOOL HeapMonitorManager::FetchClassInfo (CLASSID id)
- {
- ASSERT(Entered());
-
- FieldID *pfields;
- unsigned nfields;
- HRESULT hr = m_vminfo->GetClassFields((ClassID)id->vmid, &nfields, &pfields);
- if (EVAL(hr == S_OK))
- {
- size_t szfldinfo = FIELD_OFFSET(FieldInfoHeader, fldinfo) + sizeof(FieldInfo) * nfields;
-
- FieldInfoHeader *hdr = (FieldInfoHeader*)new(BYTE[szfldinfo]);
- if (hdr != NULL)
- {
- FieldInfo *flds = &hdr->fldinfo[0];
-
- unsigned nrefs = 0;
-
- for (unsigned i = 0; i < nfields; i++)
- {
- flds[i].id = pfields[i];
-
- hr = m_vminfo->FieldInformation(pfields[i], &flds[i].name, &flds[i].flags);
- if (hr != S_OK)
- break;
-
- if ( (flds[i].flags & JVM_FIELD_OBJECTREF)
- && !(flds[i].flags & JVM_FIELD_STATIC))
- {
- nrefs++;
- }
- }
-
- hdr->nfields = i;
- hdr->nreffields = nrefs;
-
- id->flds = hdr;
-
- unsigned nspecialclsids;
- ClassID *pspecialclsids;
- DWORD *pclsflags;
- if (m_vminfo->GetSpecialClassProperties(&nspecialclsids, &pspecialclsids, &pclsflags) == S_OK)
- {
- for (unsigned i = 0; i < nspecialclsids; i++)
- {
- if (pspecialclsids[i] == id->vmid)
- {
- DWORD flags = pclsflags[i];
-
- if (flags & JVM_CLS_HAS_DESCRIPTION)
- id->flags |= CID_FL_HAS_DESCRIPTION;
-
- break;
- }
- }
-
- CoTaskMemFree(pspecialclsids);
- CoTaskMemFree(pclsflags);
- }
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
- }
-
- return SUCCEEDED(hr);
- }
-
-
- //static
- int HeapMonitorManager::FetchClassInfoCB (ID id, PVOID cbtoken)
- {
- HeapMonitorManager *hmm = (HeapMonitorManager*)cbtoken;
-
- if (id->type == ID_CLASS)
- {
- CLASSID clsid = (CLASSID)id;
- if (clsid->flds == NULL)
- {
- hmm->FetchClassInfo(clsid);
- }
- }
-
- return 1;
- }
-
-
- PCSTR HeapMonitorManager::FetchContainerName (PSTR **prgpszDescr, CONTAINER_TYPE type, BOOL fVerbose)
- {
- PSTR pszDescr = NULL;
-
- Enter();
- {
- PSTR *rgpszDescr = *prgpszDescr;
- if (rgpszDescr == NULL)
- {
- rgpszDescr = new(PSTR[C_LAST - C_FIRST - 1]);
- if (rgpszDescr != NULL)
- {
- ZeroMemory(rgpszDescr, sizeof(PSTR)*(C_LAST - C_FIRST - 1));
- *prgpszDescr = rgpszDescr;
- }
- }
-
- if (rgpszDescr != NULL)
- {
- int iDescr = type - C_FIRST - 1;
- pszDescr = rgpszDescr[iDescr];
- if (pszDescr == NULL)
- {
- PWSTR pdescr;
- PWSTR *ppdescr1;
- PWSTR *ppdescr2;
- if (fVerbose)
- {
- ppdescr1 = NULL;
- ppdescr2 = &pdescr;
- }
- else
- {
- ppdescr1 = &pdescr;
- ppdescr2 = NULL;
- }
-
- if (m_vmheapmon->GetContainerDescription((CONTAINER_TYPE)type, ppdescr1, ppdescr2) == S_OK)
- {
- UnicodeToANSI(pdescr, -1, &pszDescr);
- rgpszDescr[iDescr] = pszDescr;
- }
- }
- }
- }
- Leave();
-
- if (pszDescr == NULL)
- pszDescr = "???";
-
- return pszDescr;
- }
-
-
- //------------------------------------------------------------------------
-
-
- HeapMonitorManager::ExpandObjectResults HeapMonitorManager::ExpandObject (
- ObjectID vmid, OBJID *pid,
- ExpandObjectAddObjectIDReferenceProc *vmidcb,
- ExpandObjectAddOBJIDReferenceProc *idcb,
- PVOID token)
- {
- OBJID id = *pid;
-
- if (id)
- {
- if (id->flags & (OID_FL_NO_REFERENCES | OID_FL_DEAD))
- return EOR_NO_REFERENCES;
-
- vmid = id->GetObjectID();
- }
-
- BOOL fExpanding;
-
- Enter();
- {
- if (!(m_flags & HMM_FL_HEAP_EXPLORED))
- {
- if (!id)
- {
- // Heap enumeration has not completed, so we must hash all
- // objects discovered here to detect cycles.
-
- id = (OBJID)LookupObject(vmid);
- if (!id)
- {
- Leave();
- return EOR_FAILED;
- }
-
- *pid = id;
- }
-
- fExpanding = !(id->flags & OID_FL_EXPANDED);
- if (fExpanding)
- id->flags |= OID_FL_EXPANDED;
- }
- else
- {
- // The heap has been completely explored, so only "special"
- // objects need to be hashed.
-
- if (!id)
- id = (OBJID)LookupID(vmid);
- fExpanding = FALSE;
- }
- }
- Leave();
-
- if (!id)
- ASSERT(!fExpanding);
-
- ExpandObjectResults result = EOR_FAILED;
-
- if (!id || !(id->flags & (OID_FL_NULL_REFERENCES | OID_FL_NO_REFERENCES)))
- {
- ClassID clsid;
- if (m_vminfo->ObjectInformation(vmid, &clsid) == S_OK)
- {
- CLASSID cls = LookupClass(clsid);
- if (cls)
- {
- result = EOR_EXPANDED;
-
- ULONG nflds = 0;
- FieldInfoHeader *flds = NULL;
-
- if (cls->flags & CID_FL_ARRAY)
- {
- if (cls->flags & CID_FL_ARRAY_OF_OBJECTS)
- {
- nflds = ULONG_MAX;
- }
- }
- else
- {
- flds = cls->flds;
- if (flds && flds->nreffields != 0)
- {
- nflds = flds->nfields;
- }
- }
-
- if (nflds != 0)
- {
- BOOL fFoundRef = FALSE;
-
- for (unsigned i = 0; i < nflds; i++)
- {
- // NOTE: The following will not work on VMs older than
- // build 3223. See the comment at the top of this
- // file.
-
- __int64 value;
- if (!flds)
- {
- if (m_vminfo->GetArrayElement(vmid, i, &value) != S_OK)
- break;
- }
- else
- {
- FieldInfo *pfld = &flds->fldinfo[i];
- if ( !(pfld->flags & JVM_FIELD_OBJECTREF)
- || (pfld->flags & JVM_FIELD_STATIC))
- {
- continue;
- }
-
- // This may validly fail for fields in variable-size objects.
- if (m_vminfo->GetObjectField(vmid, pfld->id, &value) != S_OK)
- {
- // TODO: for non-variable-size classes, set HMM_FL_INACCURATE
- continue;
- }
- }
-
- ObjectID refvmid = (ObjectID)value;
- if (refvmid)
- {
- fFoundRef = TRUE;
-
- OBJID refid = NULL;
- if (fExpanding)
- {
- refid = DiscoveredObject(refvmid);
- if (!refid)
- continue;
- }
- else
- {
- refid = (OBJID)LookupID(refvmid);
- }
- if (refid)
- (*idcb)(refid, token);
- else
- (*vmidcb)(refvmid, token);
- }
- }
-
- if (!fFoundRef)
- goto no_refs;
- }
- else
- {
- no_refs:
-
- Enter();
- {
- if (!id)
- id = (OBJID)LookupID(vmid);
- if (id)
- {
- id->flags |= OID_FL_NO_REFERENCES;
- *pid = id;
- }
- }
- Leave();
-
- result = EOR_NO_REFERENCES;
- }
- }
- }
- }
-
- return result;
- }
-
-
- BOOL HeapMonitorManager::FindObjectReferences (ObjectID vmid, SearchProc *cb, PVOID token)
- {
- ASSERT(vmid != NULL);
-
- SearchOperation findrefsop;
- findrefsop.op = SOP_REFERENCE_TO;
- findrefsop.refersto.oid = vmid;
- findrefsop.proc = cb;
- findrefsop.token = token;
-
- return RegisterSearchOperation(&findrefsop);
- }
-
-
- BOOL HeapMonitorManager::FindClassInstances (CLASSID cls, SearchProc *cb, PVOID token)
- {
- SearchOperation findinst;
- findinst.op = SOP_INSTANCE_OF;
- findinst.instanceof.cid = cls->vmid;
- findinst.proc = cb;
- findinst.token = token;
-
- return RegisterSearchOperation(&findinst);
- }
-
-
- OBJID HeapMonitorManager::CreateOBJID (ObjectID vmid)
- {
- ASSERT(Entered());
- ASSERT(!IsExecutionSuspended_Safe());
- ASSERT(!LookupID(vmid));
-
- OBJID id = new(ObjectIDWrapper());
- if (id)
- {
- id->vmid = vmid;
- id->flags = 0;
-
- if (!AddID(vmid, id))
- {
- delete(id);
- id = NULL;
-
- m_flags |= HMM_FL_INACCURATE;
- }
- }
- return id;
- }
-
-
- OBJID HeapMonitorManager::DiscoveredObject (ObjectID vmid)
- {
- OBJID id;
-
- BOOL fStatusChanged = FALSE;
-
- Enter();
- {
- id = (OBJID)LookupID(vmid);
- if (id)
- {
- if (id->flags & ID_FL_DISCOVERED)
- {
- if (!(id->flags & OID_FL_MULTIPLE_REFERENCES))
- {
- m_gcinfo.nObjectsWithMultipleReferences++;
- id->flags |= OID_FL_MULTIPLE_REFERENCES;
- fStatusChanged = TRUE;
- }
- }
- else
- {
- id->flags |= ID_FL_DISCOVERED;
- }
- }
- else
- {
- id = CreateOBJID(vmid);
- if (id)
- id->flags |= ID_FL_DISCOVERED;
- }
- }
- Leave();
-
- if (fStatusChanged)
- {
- ASSERT(id);
- SendObjectStatusChanged(id);
- }
-
- return id;
- }
-
-
- ID HeapMonitorManager::DiscoveredRoot (CONTAINER_TYPE type, UniqueID vmid, UniqueID extraid)
- {
- ID id = LookupID(vmid);
- if (!id)
- {
- switch (type)
- {
- case C_RT_CLASS:
- id = ClassLoaded(vmid);
- break;
-
- case C_RT_THREAD:
- id = ThreadCreated(vmid, TRUE);
- break;
-
- case C_RT_JIT:
- case C_RT_NATIVE:
- case C_RT_NATIVEGC:
- case C_RT_COM:
- case C_RT_INTERPRETED:
- case C_RT_FASTINTERPRETED:
- case C_RT_INTERNALFRAME:
- {
- ASSERT(m_lastthreadid);
- ASSERT(LookupID(m_lastthreadid->vmid) == m_lastthreadid);
-
- STACKID stkid = new(StackIDWrapper());
- if (stkid)
- {
- // Roots can only be discovered through heap dumping, the
- // only caller of this method - so we're only serializing
- // the one writer with multiple readers.
- Enter();
- {
- if (AddID(vmid, stkid))
- {
- stkid->vmid = vmid;
- stkid->frmtype = type;
-
- MethodID methodid = NULL;
- if ( type == C_RT_JIT
- || type == C_RT_NATIVE
- || type == C_RT_COM
- || type == C_RT_INTERPRETED
- || type == C_RT_FASTINTERPRETED)
- {
- methodid = extraid;
- }
- stkid->methodid = methodid;
-
- stkid->thd = m_lastthreadid;
-
- // StackIDs may be reported multiple times and in any order.
-
- STACKID *pparent = &stkid->thd->curframe;
- while (*pparent && stkid->vmid >= (*pparent)->vmid)
- pparent = &(*pparent)->parent;
- stkid->parent = *pparent;
- *pparent = stkid;
-
- id = stkid;
- }
- else
- {
- delete(stkid);
- }
- }
- Leave();
- }
- }
- break;
-
- default:
- Enter();
- {
- id = LookupID(vmid);
- if (!id)
- {
- ROOTID rootid = new(RootIDWrapper());
- if (rootid)
- {
- rootid->vmid = vmid;
-
- rootid->roottype = type;
- rootid->rootid1 = vmid;
- rootid->rootid2 = extraid;
-
- if (AddID(vmid, rootid))
- id = rootid;
- else
- delete(rootid);
- }
- }
- }
- Leave();
-
- break;
- }
- }
-
- if (id)
- {
- if (!(id->flags & ID_FL_DISCOVERED))
- {
- m_gcinfo.rgcRoots[type - C_FIRST - 1]++;
-
- // Currently flags of all root IDs are manipulated only on the
- // event thread.
- id->flags |= ID_FL_DISCOVERED;
- }
- }
-
- return id;
- }
-
-
- BOOL HeapMonitorManager::RegisterSearchOperation (SearchOperation *searchitem)
- {
- BOOL result = FALSE;
-
- SearchHeapInfoCallback *hicb = m_searchcb;
- if (!hicb)
- hicb = new(SearchHeapInfoCallback(this));
-
- if (hicb)
- {
- Enter();
- {
- if (m_searchcb == hicb)
- {
- ;
- }
- else
- {
- if (!m_searchcb)
- {
- m_searchcb = hicb;
- }
- else
- {
- hicb->Release();
- hicb = m_searchcb;
- }
- }
-
- SearchOperation *newworkitem = new(SearchOperation());
- if (newworkitem)
- {
- *newworkitem = *searchitem;
-
- hicb->AddSearchOperation(newworkitem);
-
- result = RegisterHeapWalk(hicb, JVM_WALKHEAP_NO_ROOTS);
- }
- }
- Leave();
- }
-
- return result;
- }
-
-
- BOOL HeapMonitorManager::RegisterHeapWalk (IWalkHeapCallback *cb, DWORD HeapWalkFlags)
- {
- BOOL result = TRUE;
-
- if (!m_vmheapmon2)
- {
- result = FALSE;
- }
- else
- {
- Enter();
- {
- BOOL fQueueSearch = FALSE;
- BOOL fScanHeapNow = FALSE;
-
- if (GetCurrentThreadId() == m_tid)
- {
- // Called on the gui thread. Check if execution is about to resume.
- // If not, queue a request to search and wake up the heap thread.
-
- if (!IsExecutionSuspended_Safe())
- {
- fQueueSearch = TRUE;
- }
- else
- {
- result = FALSE;
- }
- }
- else
- {
- // Called from the heap thread. If the END container has been
- // received, we can initiate the search directly. If not, queue a
- // request to search when END is received.
-
- fQueueSearch = TRUE;
-
- if (m_flags & HMM_FL_HEAP_EXPLORED)
- {
- fScanHeapNow = TRUE;
- }
- }
-
- if (fQueueSearch)
- {
- // Tack this request onto the search list. When the heap thread
- // is ready, it will remove the entire list and search for all of
- // the objects at once in a single heap dump.
-
- PendingHeapWalk *workitem = new(PendingHeapWalk());
- result = (workitem != NULL);
- if (result)
- {
- (workitem->cb = cb)->AddRef();
- workitem->HeapWalkFlags = HeapWalkFlags;
-
- workitem->next = m_heapwalks;
- m_heapwalks = workitem;
- }
- }
-
- if (result)
- {
- if (fScanHeapNow)
- {
- Leave();
-
- StartHeapDumpProgressIndicator();
-
- SetStatusText("Searching...");
-
- m_vmheapmon2->WalkHeap(cb, HeapWalkFlags);
-
- StopHeapDumpProgressIndicator();
-
- SetStatusText("Search complete.");
-
- return TRUE;
- }
- else
- {
- SetEvent(m_hresumeevt);
- }
- }
- }
- Leave();
- }
-
- return result;
- }
-
-
- //------------------------------------------------------------------------
-
-
- BOOL HeapMonitorManager::ToggleObjectTracking (OBJID obj, ObjectID vmid)
- {
- ASSERT(obj != NULL || vmid != NULL);
- if (vmid == NULL)
- ASSERT(obj->flags & OID_FL_DEAD);
-
- BOOL result;
-
- Enter();
- {
- if (obj == NULL)
- obj = LookupObject(vmid);
- result = (obj != NULL);
- if (result)
- {
- if (!(obj->flags & OID_FL_TRACKED))
- {
- TrackedObjectList *trkent = *FindTrackedObjectEntry(obj);
- if (obj->flags & ALL_OID_NONTRANSIENT_FLAGS)
- ASSERT(trkent != NULL);
-
- if (trkent != NULL)
- {
- ASSERT(trkent->vmhid != NULL);
- obj->flags |= OID_FL_TRACKED;
- }
- else
- {
- trkent = CreateTrackedObjectEntry(obj);
-
- if (trkent != NULL)
- {
- obj->flags |= OID_FL_TRACKED;
- }
- else
- {
- result = FALSE;
- }
- }
- }
- else
- {
- TrackedObjectList **ptrkent = FindTrackedObjectEntry(obj);
- ASSERT(*ptrkent != NULL);
-
- obj->flags -= OID_FL_TRACKED;
-
- if (!(obj->flags & ALL_OID_NONTRANSIENT_FLAGS))
- {
- DestroyTrackedObjectEntry(ptrkent);
- }
- }
- }
- }
- Leave();
-
- if (result)
- SendObjectStatusChanged(obj);
-
- return result;
- }
-
-
- BOOL HeapMonitorManager::SetObjectTag (OBJID obj, PCSTR newtag)
- {
- ASSERT(obj != NULL);
-
- BOOL result = TRUE;
- BOOL update = TRUE;
-
- if (newtag != NULL || (obj->flags & OID_FL_TAGGED))
- {
- PSTR newtagmem = NULL;
- if (newtag != NULL)
- {
- int len = strlen(newtag);
- newtagmem = new(CHAR[len+1]);
- if (newtagmem != NULL)
- CopyMemory(newtagmem, newtag, len+1);
- else
- result = FALSE;
- }
-
- if (result)
- {
- Enter();
- {
- TrackedObjectList **ptrkent = FindTrackedObjectEntry(obj);
- TrackedObjectList *trkent = *ptrkent;
- if (obj->flags & ALL_OID_NONTRANSIENT_FLAGS)
- ASSERT(trkent != NULL);
-
- if (trkent == NULL)
- {
- trkent = CreateTrackedObjectEntry(obj);
- if (trkent == NULL)
- {
- result = FALSE;
- update = FALSE;
- delete(newtagmem);
- }
- }
-
- if (trkent != NULL)
- {
- if (trkent->tag != NULL)
- delete(trkent->tag);
-
- if (newtagmem == NULL)
- {
- ASSERT(trkent->tag != NULL);
- ASSERT(obj->flags & OID_FL_TAGGED);
-
- trkent->tag = NULL;
- obj->flags -= OID_FL_TAGGED;
- update = TRUE;
-
- if (!(obj->flags & ALL_OID_NONTRANSIENT_FLAGS))
- DestroyTrackedObjectEntry(ptrkent);
- }
- else
- {
- trkent->tag = newtagmem;
- obj->flags |= OID_FL_TAGGED;
- }
- }
- }
- Leave();
-
- if (update)
- SendObjectStatusChanged(obj);
- }
- }
-
- return result;
- }
-
-
- PCSTR HeapMonitorManager::GetObjectTag (OBJID obj)
- {
- // Use of return value must be externally synchronized
- ASSERT(Entered());
-
- PCSTR tag;
-
- if (obj->flags & OID_FL_TAGGED)
- {
- TrackedObjectList *trkent = *FindTrackedObjectEntry(obj);
- ASSERT(trkent != NULL);
- tag = trkent->tag;
- }
- else
- {
- tag = NULL;
- }
-
- return tag;
- }
-
-
- int HeapMonitorManager::IterateSpecialObjects (SPECIALOBJITERFN *cb, PVOID token)
- {
- int result = 1;
-
- for (TrackedObjectList *trkent = m_trackedobjs; trkent != NULL; )
- {
- TrackedObjectList *next = trkent->next;
- result = (*cb)(trkent->obj, token);
- if (result <= 0)
- break;
- trkent = next;
- }
-
- return result;
- }
-
-
- HeapMonitorManager::TrackedObjectList **HeapMonitorManager::FindTrackedObjectEntry (OBJID obj)
- {
- TrackedObjectList **ptrkent = &m_trackedobjs;
- for (;;)
- {
- TrackedObjectList *trkent = *ptrkent;
- if (trkent == NULL || trkent->obj == obj)
- break;
- ptrkent = &trkent->next;
- }
- return ptrkent;
- }
-
-
- HeapMonitorManager::TrackedObjectList *HeapMonitorManager::CreateTrackedObjectEntry (OBJID obj)
- {
- ASSERT(Entered());
- ASSERT(!(obj->flags & OID_FL_DEAD));
-
- TrackedObjectList *trkent = new(TrackedObjectList());
- if (trkent != NULL)
- {
- ZeroMemory(trkent, sizeof(*trkent));
-
- if (m_vminfo->GetHandlesToObjects(1, &obj->vmid, &trkent->vmhid) == S_OK)
- {
- trkent->obj = obj;
- EVAL(m_vminfo->ObjectInformation(obj->vmid, &trkent->vmclsid) == S_OK);
-
- trkent->next = m_trackedobjs;
- m_trackedobjs = trkent;
- }
- else
- {
- delete(trkent);
- trkent = NULL;
- }
- }
-
- return trkent;
- }
-
-
- VOID HeapMonitorManager::DestroyTrackedObjectEntry (TrackedObjectList **ptrkent)
- {
- if ((*ptrkent)->vmhid != NULL)
- EVAL(m_vminfo->FreeHandlesToObjects(1, &(*ptrkent)->vmhid) == S_OK);
-
- TrackedObjectList *trash = *ptrkent;
- *ptrkent = trash->next;
- delete(trash);
- }
-
-
- //------------------------------------------------------------------------
-
-
- //static
- VOID HeapMonitorManager::StoppedExecutionCB (IHeapMonitorClient *client, PVOID token)
- {
- client->OnStoppedExecution();
- }
-
-
- VOID HeapMonitorManager::SendSuspendedEvent ()
- {
- IterateClients(HMC_UNMASKABLE_EVENTS, &StoppedExecutionCB, NULL);
- }
-
-
- //static
- VOID HeapMonitorManager::ResumeExecutionCB (IHeapMonitorClient *client, PVOID token)
- {
- client->OnResumeExecution();
- }
-
-
- VOID HeapMonitorManager::SendResumingEvent ()
- {
- IterateClients(HMC_UNMASKABLE_EVENTS, &ResumeExecutionCB, NULL);
- }
-
-
- //static
- VOID HeapMonitorManager::SendClosingEventCB (IHeapMonitorClient *client, PVOID token)
- {
- client->OnClose();
- }
-
-
- VOID HeapMonitorManager::SendClosingEvent ()
- {
- IterateClients(HMC_UNMASKABLE_EVENTS, &SendClosingEventCB, NULL);
- }
-
-
- //static
- VOID HeapMonitorManager::SendThreadCreatedEventCB (IHeapMonitorClient *client, PVOID token)
- {
- THREADID thd = (THREADID)token;
-
- client->OnThreadCreated(thd);
- }
-
-
- VOID HeapMonitorManager::SendThreadCreatedEvent (THREADID thd)
- {
- IterateClients(HMC_THREAD_EVENTS, &SendThreadCreatedEventCB, (PVOID)thd);
- }
-
-
- //static
- VOID HeapMonitorManager::SendDestroyThreadEventCB (IHeapMonitorClient *client, PVOID token)
- {
- THREADID thd = (THREADID)token;
-
- client->OnDestroyThread(thd);
- }
-
-
- VOID HeapMonitorManager::SendDestroyThreadEvent (THREADID thd)
- {
- IterateClients(HMC_THREAD_EVENTS, &SendDestroyThreadEventCB, (PVOID)thd);
- }
-
-
- //static
- VOID HeapMonitorManager::SendPackageCreatedEventCB (IHeapMonitorClient *client, PVOID token)
- {
- PKGID newpkgid = (PKGID)token;
-
- client->OnPackageCreated(newpkgid);
- }
-
-
- VOID HeapMonitorManager::SendPackageCreatedEvent (PKGID newpkgid)
- {
- IterateClients(HMC_CLASS_EVENTS, &SendPackageCreatedEventCB, (PVOID)newpkgid);
- }
-
-
- //static
- VOID HeapMonitorManager::SendClassLoadedEventCB (IHeapMonitorClient *client, PVOID token)
- {
- CLASSID newclsid = (CLASSID)token;
-
- client->OnClassLoaded(newclsid);
- }
-
-
- VOID HeapMonitorManager::SendClassLoadedEvent (CLASSID newclsid)
- {
- IterateClients(HMC_CLASS_EVENTS, &SendClassLoadedEventCB, (PVOID)newclsid);
- }
-
-
- //static
- VOID HeapMonitorManager::SendUnloadClassEventCB (IHeapMonitorClient *client, PVOID token)
- {
- CLASSID cls = (CLASSID)token;
-
- client->OnUnloadClass(cls);
- }
-
-
- VOID HeapMonitorManager::SendUnloadClassEvent (CLASSID cls)
- {
- IterateClients(HMC_CLASS_EVENTS, &SendUnloadClassEventCB, (PVOID)cls);
- }
-
-
- //static
- VOID HeapMonitorManager::RootReferencedCB (IHeapMonitorClient *client, PVOID token)
- {
- RootReferencesEventInfo *pinfo = (RootReferencesEventInfo*)token;
-
- client->RootReferences(pinfo);
- }
-
-
- VOID HeapMonitorManager::SendRootReferencesEvent (RootReferencesEventInfo *pinfo)
- {
- IterateClients(HMC_ROOT_EVENTS, &RootReferencedCB, pinfo);
- }
-
-
- //static
- VOID HeapMonitorManager::ObjectStatusChangedCB (IHeapMonitorClient *client, PVOID token)
- {
- client->OnObjectStatusChange((OBJID)token);
- }
-
-
- VOID HeapMonitorManager::SendObjectStatusChanged (OBJID obj)
- {
- IterateClients(HMC_OBJECT_EVENTS, &ObjectStatusChangedCB, obj);
- }
-
-
- //static
- VOID HeapMonitorManager::RootDiscoveryCompleteCB (IHeapMonitorClient *client, PVOID token)
- {
- client->RootDiscoveryComplete();
- }
-
-
- VOID HeapMonitorManager::SendRootDiscoveryComplete ()
- {
- IterateClients(HMC_HEAP_EVENTS, &RootDiscoveryCompleteCB, NULL);
- }
-
-
- //static
- VOID HeapMonitorManager::ObjectDiscoveryCompleteCB (IHeapMonitorClient *client, PVOID token)
- {
- client->ObjectDiscoveryComplete();
- }
-
-
- VOID HeapMonitorManager::SendObjectDiscoveryComplete ()
- {
- IterateClients(HMC_HEAP_EVENTS, &ObjectDiscoveryCompleteCB, NULL);
- }
-
-
- VOID HeapMonitorManager::Stopped ()
- {
- ASSERT(!Entered());
- ASSERT(m_flags & HMM_FL_STOPPED);
-
- WaitForSingleObject(m_hresumeevt, INFINITE);
- }
-
-
- CLASSID HeapMonitorManager::ClassLoaded (ClassID vmid, PWSTR name)
- {
- ASSERT(!Entered());
-
- CLASSID cls = NULL;
- CLASSID ret = NULL;
-
- Enter();
- {
- ret = (CLASSID)LookupID(vmid);
- if (!ret)
- {
- cls = new(ClassIDWrapper());
- if (cls)
- {
- BOOL success = TRUE;
- PKGID pkgid = NULL;
-
- PWSTR sep = name;
- if (*sep == L'[')
- {
- sep++;
- while (*sep == L'[')
- sep++;
- if (*sep == L'L')
- sep++;
- }
-
- PWSTR pkgnamestart = sep;
- PWCHAR pch = sep;
- while (*pch != L'\0')
- {
- if (*pch == L'.' || *pch == L'/')
- {
- *pch = L'\0';
-
- pkgid = LookupPackage(pkgid, pkgnamestart);
- if (!pkgid)
- {
- // TODO: can continue to create class, include subpkg in name
- success = FALSE;
- break;
- }
-
- // Check if another thread created the class wrapper, in
- // case LookupPackage left the lock.
-
- CLASSID cls2 = (CLASSID)LookupID(vmid);
- if (cls2)
- {
- ret = cls2;
- success = FALSE;
- break;
- }
-
- *pch = L'.';
- sep = pch+1;
- }
-
- pch++;
- }
-
- if (success)
- {
- ASSERT(!LookupID(vmid));
-
- if (AddID(vmid, cls))
- {
- cls->pkg = pkgid;
- }
- else
- {
- success = FALSE;
- }
- }
-
- if (success)
- {
- if (name[0] == L'[')
- {
- cls->flags |= CID_FL_ARRAY;
-
- if (name[1] == L'L')
- {
- cls->flags |= CID_FL_ARRAY_OF_OBJECTS;
- }
- }
-
- if (m_flags & HMM_FL_VM_INITIALIZED)
- {
- success = FetchClassInfo(cls);
- }
- }
-
- if (success)
- {
- ASSERT(cls);
-
- ret = cls;
- }
- else
- {
- delete(cls);
- cls = NULL;
- }
- }
- }
- }
- Leave();
-
- if (cls)
- SendClassLoadedEvent(cls);
-
- return ret;
- }
-
-
- CLASSID HeapMonitorManager::ClassLoaded (ClassID vmid)
- {
- ASSERT(!Entered());
-
- CLASSID cls = NULL;
-
- PSTR pclsname;
- HRESULT hr = m_vminfo->ClassInformation(
- vmid,
- &pclsname,
- NULL, // source file
- NULL, // methods count
- NULL, // methods
- NULL); // instance creation count
- if (SUCCEEDED(hr) && pclsname)
- {
- PWSTR pwclsname;
-
- hr = Utf8ToUnicode(pclsname, &pwclsname);
-
- if (SUCCEEDED(hr) && pwclsname)
- {
- cls = ClassLoaded(vmid, pwclsname);
-
- delete(pwclsname);
- }
-
- CoTaskMemFree(pclsname);
- }
-
- return cls;
- }
-
-
- VOID HeapMonitorManager::ClassUnloaded (ClassID vmid)
- {
- CLASSID cls = (CLASSID)LookupID(vmid);
- if (cls)
- {
- SendUnloadClassEvent(cls);
-
- delete cls;
- }
- }
-
-
- THREADID HeapMonitorManager::ThreadCreated (ThreadID vmid, BOOL ghost)
- {
- THREADID id;
-
- Enter();
- {
- id = (THREADID)LookupID(vmid);
- if (!id)
- {
- id = new(ThreadIDWrapper());
- if (id)
- {
- if (AddID(vmid, id))
- {
- if (ghost)
- id->type = ID_GHOST_THREAD;
- }
- else
- {
- delete(id);
- id = NULL;
- }
- }
- }
- else if (!ghost)
- {
- ASSERT(id->type == ID_GHOST_THREAD);
- id->type = ID_THREAD;
- }
- }
- Leave();
-
- if (id && !ghost)
- {
- SendThreadCreatedEvent(id);
- }
-
- return id;
- }
-
-
- HRESULT HeapMonitorManager::ThreadNameChanged (ThreadID vmid, PWSTR newname)
- {
- // TODO
- return E_NOTIMPL;
- }
-
-
- VOID HeapMonitorManager::ThreadDestroyed (ThreadID vmid)
- {
- THREADID thdid = NULL;
-
- // Remove it from the map, serializing with IterateIDs and heap dumping.
-
- Enter();
- {
- thdid = (THREADID)LookupID(vmid);
- if (thdid)
- {
- if (m_flags & HMM_FL_STOPPED)
- {
- thdid->flags |= TID_FL_DEAD;
- thdid = NULL;
- }
- else
- {
- DeleteID(thdid);
- }
- }
- }
- Leave();
-
- if (thdid)
- {
- // Clients can no longer "discover" the thread, but they may still
- // have references to it. Notify clients that the ID is about to be
- // deleted.
-
- SendDestroyThreadEvent(thdid);
-
- delete(thdid);
- }
- }
-
-
- //static
- int HeapMonitorManager::MarkEmptyRootsCB (ID id, PVOID token)
- {
- #ifndef NDEBUG
- HeapMonitorManager *hmm = (HeapMonitorManager*)token;
- ASSERT(hmm->Entered());
- #endif // !NDEBUG
-
- if (id->type >= ID_FIRST_TRANSIENT)
- {
- BOOL fReport = FALSE;
-
- switch (id->type)
- {
- case ID_ROOT:
- ROOTID rootid;
- rootid = (ROOTID)id;
- fReport = !(rootid->flags & RID_FL_HAS_REFERENCES);
- break;
-
- case ID_STACKFRAME:
- STACKID stkid;
- stkid = (STACKID)id;
- fReport = !(stkid->flags & SID_FL_HAS_REFERENCES);
- break;
- }
-
- if (fReport)
- id->flags |= ID_FL_MARKED_EMPTY_ROOT;
- }
-
- return 1;
- }
-
-
- //static
- int HeapMonitorManager::ReportEmptyRootsCB (ID id, PVOID token)
- {
- HeapMonitorManager *hmm = (HeapMonitorManager*)token;
-
- ASSERT(!hmm->Entered());
-
- if (id->flags & ID_FL_MARKED_EMPTY_ROOT)
- {
- hmm->Enter();
- {
- id->flags = ((id->flags & ~ID_FL_MARKED_EMPTY_ROOT) | ID_FL_REPORTED_EMPTY_ROOT);
- }
- hmm->Leave();
-
- RootReferencesEventInfo info;
-
- switch (id->type)
- {
- case ID_ROOT:
- ROOTID rootid;
- rootid = (ROOTID)id;
- if (!(rootid->flags & RID_FL_HAS_REFERENCES))
- {
- info.type = rootid->roottype;
- info.id1 = rootid->rootid1;
- info.id2 = rootid->rootid2;
- }
- break;
-
- case ID_STACKFRAME:
- STACKID stkid;
- stkid = (STACKID)id;
- if (!(stkid->flags & SID_FL_HAS_REFERENCES))
- {
- info.type = stkid->frmtype;
- info.id1 = stkid->vmid;
- info.id2 = stkid->methodid;
- }
- break;
-
- default:
- ASSERT(!"unknown marked id type");
- return 1;
- }
-
- info.nrefs = 0;
- info.rgrefs = NULL;
- info.rgflags = NULL;
- info.rootid = id;
-
- hmm->IterateClients(HMC_ROOT_EVENTS, &RootReferencedCB, &info);
- }
-
- return 1;
- }
-
-
- //static
- int HeapMonitorManager::ResetEmptyRootsCB (ID id, PVOID token)
- {
- ASSERT(!(id->flags & ID_FL_MARKED_EMPTY_ROOT));
-
- id->flags &= ~ID_FL_REPORTED_EMPTY_ROOT;
-
- return 1;
- }
-
-
- //------------------------------------------------------------------------
-
-
- STDMETHODIMP HeapMonitorManager::Initialize (
- LPCSTR pclass_file_name,
- IJavaEventMonitorIDInfo *pmonitor_info,
- DWORD java_flags,
- DWORD *prequested_events)
- {
- HRESULT hr;
-
- hr = pmonitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo2, (PVOID*)&m_vminfo);
-
- if (hr == S_OK)
- {
- hr = pmonitor_info->QueryInterface(IID_IJavaHeapMonitor, (PVOID*)&m_vmheapmon);
- }
-
- if (hr == S_OK)
- {
- // Ignore failure.
- pmonitor_info->QueryInterface(IID_IJavaHeapMonitor2, (PVOID*)&m_vmheapmon2);
- }
-
- if (hr == S_OK)
- {
- IHeapInfoCallback *heapcb;
- hr = QueryInterface(IID_IHeapInfoCallback, (PVOID*)&heapcb);
- if (hr == S_OK)
- {
- hr = m_vmheapmon->GetHeapInfo(heapcb);
- heapcb->Release();
- }
- }
-
- if (hr == S_OK)
- {
- DWORD caps;
- hr = m_vmheapmon->ModifyHeapMonitorCapabilities(JVM_HEAPMON_OBJECT_AGE, TRUE, &caps);
- if (SUCCEEDED(hr) && (caps & JVM_HEAPMON_OBJECT_AGE))
- m_flags |= HMM_FL_OBJECT_AGING;
-
- hr = S_OK;
- }
-
- if (hr == S_OK)
- {
- IJavaEventMonitorIDInfo4 *pinfo4;
- if (pmonitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo4, (PVOID*)&pinfo4) == S_OK)
- {
- pinfo4->SetMonitorInitializationOptions( JVM_INIT_OPT_FP_SAFE_METHOD_CALLS
- | JVM_INIT_OPT_GC_SAFE_METHOD_CALLS
- | JVM_INIT_OPT_RETURN_VALUE_NOT_NEEDED
- | JVM_INIT_OPT_WONT_TOGGLE_METHOD_CALL_EVENTS);
- // | JVM_INIT_OPT_DONT_NEED_ALLOCATION_CALLBACK);
-
- pinfo4->Release();
- }
- }
-
- *prequested_events = JVM_MONITOR_CLASS_LOADS | JVM_MONITOR_THREADS;
-
- // Only S_OK is respected by the VM.
- if (hr != S_OK)
- ASSERT(!"heap monitor failed to initialize");
-
- return hr;
- }
-
-
- STDMETHODIMP HeapMonitorManager::NotifyEvent (JVM_EVENT_TYPE event, UniqueID event_id)
- {
- HRESULT hr = E_FAIL;
-
- switch (event)
- {
- case JVM_EVENT_TYPE_THREAD_CREATE:
- if (ThreadCreated((ThreadID)event_id, FALSE))
- hr = S_OK;
- break;
-
- case JVM_EVENT_TYPE_THREAD_DESTROY:
- ThreadDestroyed((ThreadID)event_id);
- hr = S_OK;
- break;
-
- case JVM_EVENT_TYPE_CLASS_LOAD_FINISHED:
- if (ClassLoaded((ClassID)event_id))
- hr = S_OK;
- break;
-
- case JVM_EVENT_TYPE_CLASS_UNLOAD:
- ClassUnloaded((ClassID)event_id);
- hr = S_OK;
- break;
-
- case JVM_EVENT_TYPE_GC_STARTED:
- case JVM_EVENT_TYPE_GC_FINISHED:
- if (m_flags & HMM_FL_CLOSED)
- DestroyNow();
- hr = S_OK;
- break;
- }
-
- return hr;
- }
-
-
- STDMETHODIMP HeapMonitorManager::MethodEntry (MethodID method_id, StackID stack_id)
- {
- return E_FAIL;
- }
-
-
- STDMETHODIMP HeapMonitorManager::MethodExit (StackID stack_id)
- {
- return E_FAIL;
- }
-
-
- STDMETHODIMP HeapMonitorManager::ExecuteByteCode (MethodID method_id, BYTE_CODE *pbyte_code, DWORD byte_code_offset)
- {
- return E_FAIL;
- }
-
-
- STDMETHODIMP HeapMonitorManager::ExecuteSourceLine (MethodID method_id, DWORD line_number)
- {
- return E_FAIL;
- }
-
-
- STDMETHODIMP HeapMonitorManager::NotifyEvent2 (JVM_EVENT_TYPE2 event2, UniqueID first_event_id, UniqueID second_event_id)
- {
- HRESULT hr = E_FAIL;
-
- switch (event2)
- {
- case JVM_EVENT_TYPE2_INITIALIZED:
- Enter();
- {
- IterateIDs_Safe(&FetchClassInfoCB, this);
- m_flags |= HMM_FL_VM_INITIALIZED;
- }
- Leave();
- hr = S_OK;
- break;
- }
-
- return hr;
- }
-
-
- STDMETHODIMP HeapMonitorManager::MethodExit2 (MethodID method_id, StackID stack_id)
- {
- return E_FAIL;
- }
-
-
- STDMETHODIMP HeapMonitorManager::GetPossibleEventCategories (DWORD *ppossible_events)
- {
- *ppossible_events = JVM_MONITOR_CLASS_LOADS | JVM_MONITOR_THREADS;
- return S_OK;
- }
-
-
- #ifdef DEBUG
-
- int CountMultiRefObjects (ID id, PVOID token)
- {
- unsigned *pcount = (unsigned*)token;
-
- if (id->type == ID_OBJECT)
- {
- OBJID obj = (OBJID)id;
-
- if (obj->flags & OID_FL_MULTIPLE_REFERENCES)
- {
- *pcount = *pcount + 1;
- }
- }
-
- return 1;
- }
-
- #endif // DEBUG
-
-
- STDMETHODIMP HeapMonitorManager::BeginContainer (CONTAINER_TYPE type, UniqueID id1, UniqueID id2)
- {
- HRESULT hr = S_OK;
-
- ID rootid = NULL;
-
- switch (type)
- {
- case C_BEGIN:
- {
- BOOL fSendSuspendedEvent = FALSE;
- ULONG NumTrackedObjectChanges = 0;
-
- Enter();
- {
- #ifdef DEBUG
- m_HeapDumpThreadId = GetCurrentThreadId();
- #endif // DEBUG
-
- DWORD newflags = m_flags;
-
- m_HeapInfoNeeded = m_InfoMaskUnion;
-
- if (newflags & HMM_FL_CLOSED)
- ASSERT(!(newflags & HMM_FL_STOP));
-
- if (newflags & HMM_FL_STOP)
- {
- newflags = (newflags & ~HMM_FL_STOP) | HMM_FL_STOPPED;
-
- m_HeapInfoNeeded |= m_StoppedInfoMaskUnion;
-
- fSendSuspendedEvent = TRUE;
- }
-
- newflags = (newflags & ~HMM_FL_HEAP_EXPLORED) | HMM_FL_EXPLORING_HEAP;
-
- m_flags = newflags;
-
- ZeroMemory(&m_gcinfo, FIELD_OFFSET(PerGCInformation, prev));
-
- m_gcinfo.iGC = ++m_iGC;
-
- if (fSendSuspendedEvent)
- {
- // Before notifying clients, update any OBJID's that were kept
- // from the last gc.
-
- for (TrackedObjectList *trkent = m_trackedobjs; trkent; trkent = trkent->next)
- {
- if (trkent->vmhid)
- {
- OBJID obj = trkent->obj;
- ASSERT(!(obj->flags & OID_FL_DEAD));
-
- ObjectID vmid = obj->GetObjectID();
-
- EVAL(m_vminfo->GetObjectsFromHandles(1, &trkent->vmhid, &obj->vmid) == S_OK);
-
- if (obj->vmid)
- {
- trkent->fStatusChanged = (obj->vmid != vmid);
- }
- else
- {
- // VM automatically cleans this up
- ASSERT(!trkent->vmhid);
-
- trkent->fStatusChanged = TRUE;
-
- obj->flags |= OID_FL_DEAD;
-
- TRASH(obj->vmid);
-
- m_idmap.DeleteID(vmid);
- m_IDMapChangeCount++;
- }
-
- if (trkent->fStatusChanged)
- NumTrackedObjectChanges++;
- }
- }
- }
-
- if (!(m_HeapInfoNeeded & HMC_ALL_HEAPCB_INFO))
- {
- // No information collected via IHeapInfoCallback is needed.
- // We'll get a C_END notification but nothing more.
- hr = E_FAIL;
- }
-
- // When we leave the lock, new clients will see we're in a stopped
- // state, so the ids need to already be cleaned up.
-
- m_idmap.FilterIDs(&ResetPerGCIDInfo, this);
- }
- Leave();
-
- if (m_HeapInfoNeeded)
- {
- StartHeapDumpProgressIndicator();
-
- SetStatusText("Collecting heap roots...");
- }
-
- if (fSendSuspendedEvent)
- {
- SendSuspendedEvent();
- }
-
- // Report any changes in tracked objects.
-
- while (NumTrackedObjectChanges)
- {
- Enter();
- {
- for (TrackedObjectList *trkent = m_trackedobjs; trkent; trkent = trkent->next)
- {
- if (trkent->fStatusChanged)
- {
- trkent->fStatusChanged = FALSE;
-
- Leave();
- {
- NumTrackedObjectChanges--;
- IncProgressIndicator();
-
- SendObjectStatusChanged(trkent->obj);
- }
- Enter();
-
- break;
- }
- }
- }
- Leave();
- }
-
- m_lastthreadid = NULL;
-
- break;
- }
-
- case C_END:
- {
- m_gcinfo.InfoMaskCollected = (m_HeapInfoNeeded & ~HMC_INFO_COUNT_MONITORS);
-
- if (m_InfoMaskUnion & HMC_INFO_COUNT_MONITORS)
- {
- if (m_vminfo->GetMonitorUsage(&m_gcinfo.nObjectMonitors) == S_OK)
- m_gcinfo.InfoMaskCollected |= HMC_INFO_COUNT_MONITORS;
- }
-
- #ifdef DEBUG
- unsigned count = 0;
- IterateIDs_Safe(&CountMultiRefObjects, &count);
- ASSERT(count == m_gcinfo.nObjectsWithMultipleReferences);
- #endif // DEBUG
-
- if (m_gcinfo.InfoMaskCollected)
- {
- PerGCInformation *info = new(PerGCInformation());
- if (info)
- {
- CopyMemory(info, &m_gcinfo, sizeof(m_gcinfo));
- if (info->next)
- info->next->prev = info;
- m_gcinfo.next = info;
- }
- }
-
- SendObjectDiscoveryComplete();
-
- BOOL fChangedToRunning = FALSE;
-
- Enter();
- {
- m_flags = (m_flags & ~HMM_FL_EXPLORING_HEAP) | HMM_FL_HEAP_EXPLORED;
-
- BOOL fStopped = (m_flags & HMM_FL_STOPPED);
-
- Leave();
- {
- StopHeapDumpProgressIndicator();
-
- if (fStopped)
- {
- if (!(m_flags & HMM_FL_INACCURATE))
- {
- CHAR buf[200];
- if (m_gcinfo.InfoMaskCollected & HMC_INFO_HEAP_OBJECTS)
- {
- wsprintf(buf, "Heap dump completed. %u objects, %u bytes.",
- m_gcinfo.GetTotalNumObjects(), m_gcinfo.GetTotalSizeOfObjects());
- }
- else
- {
- wsprintf(buf, "Heap dump completed.");
- }
- SetStatusText(buf);
- }
- else
- {
- SetStatusText("Heap dump finished...but errors occurred and information may not be complete.");
- }
-
- IndicateStopped();
-
- for (;;)
- {
- Stopped();
-
- Enter();
- {
- for (;;)
- {
- PendingHeapWalk *heapwalk = m_heapwalks;
- if (!heapwalk)
- break;
-
- m_heapwalks = NULL;
-
- Leave();
- {
- if (!(m_flags & HMM_FL_PROGRESS_INDICATOR))
- {
- if (StartHeapDumpProgressIndicator())
- SetStatusText("Searching...");
- }
-
- do
- {
- if (heapwalk->cb->BeginDump() == S_OK)
- {
- m_vmheapmon2->WalkHeap(heapwalk->cb, heapwalk->HeapWalkFlags);
-
- heapwalk->cb->EndDump();
- }
-
- heapwalk->cb->Release();
-
- PendingHeapWalk *trash = heapwalk;
- heapwalk = heapwalk->next;
- delete(trash);
- }
- while (heapwalk);
- }
- Enter();
- }
-
- if (m_flags & HMM_FL_PROGRESS_INDICATOR)
- {
- Leave();
- {
- StopHeapDumpProgressIndicator();
-
- SetStatusText("Search complete.");
- }
- Enter();
- }
-
- if (m_flags & HMM_FL_GO)
- goto entered;
- }
- Leave();
- }
-
- //Enter();
- entered:
- ASSERT(Entered());
-
- m_flags &= ~(HMM_FL_STOPPED | HMM_FL_HEAP_EXPLORED | HMM_FL_GO | HMM_FL_INACCURATE);
- fChangedToRunning = TRUE;
- }
- else
- {
- Enter();
- }
- }
- ASSERT(Entered());
-
- #ifdef DEBUG
- m_HeapDumpThreadId = INVALID_THREAD_ID;
- #endif // DEBUG
- }
- Leave();
-
- // The STOPPED flag must be cleared before notifying clients. New
- // clients created in this time window will pick this up and not
- // pre-populate themselves with soon-to-be-stale state. We will
- // block until the client is created when attempting to send them
- // notification that we are resuming.
-
- if (fChangedToRunning)
- {
- SendResumingEvent();
-
- IndicateRunning();
- }
-
- SetStatusText("");
-
- if (m_HeapInfoNeeded & HMC_ALL_HEAPCB_INFO)
- {
- // Now that all clients see that we are in a running state, we
- // can do this outside the lock.
-
- m_rootrefs.Reset();
-
- m_idmap.FilterIDs(&DeleteTransientIDs, this);
- }
-
- if (m_flags & HMM_FL_CLOSED)
- DestroyNow();
- }
- break;
-
- case C_RT_THREAD:
- case C_RT_CLASS:
- case C_RT_JIT:
- case C_RT_NATIVE:
- case C_RT_NATIVEGC:
- case C_RT_COM:
- case C_RT_INTERPRETED:
- case C_RT_FASTINTERPRETED:
- case C_RT_INTERNALFRAME:
- if (m_HeapInfoNeeded & HMC_INFO_HEAP_ROOTS)
- {
- rootid = DiscoveredRoot(type, id1, id2);
- if (rootid)
- {
- if (rootid->type == ID_THREAD || rootid->type == ID_GHOST_THREAD)
- m_lastthreadid = (THREADID)rootid;
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
- }
- break;
-
- case C_HEAP:
-
- if (m_HeapInfoNeeded & HMC_INFO_HEAP_ROOTS)
- {
- // If a container has no references, we may never get a
- // RootReferences call for it, so clients never get an
- // AddRootReferences call, so clients may never know about the
- // root.
-
- Enter();
- {
- ULONG changestart;
-
- if (IsEventRequested(HMC_ROOT_EVENTS))
- {
- ULONG newchangecount = m_IDMapChangeCount;
-
- do
- {
- changestart = newchangecount;
-
- IterateIDs_Safe(&MarkEmptyRootsCB, this);
-
- Leave();
- {
- IterateIDs_Safe(&ReportEmptyRootsCB, this);
- }
- Enter();
-
- newchangecount = m_IDMapChangeCount;
- }
- while (changestart != newchangecount);
-
- IterateIDs_Safe(&ResetEmptyRootsCB, this);
- }
- }
- Leave();
-
- SendRootDiscoveryComplete();
- }
-
- if (m_flags & HMM_FL_STOPPED)
- {
- SetStatusText("Examining heap objects...");
- }
-
- if (!(m_HeapInfoNeeded & (HMC_INFO_HEAP_OBJECTS | HMC_INFO_HEAP_OBJECT_REFS)))
- {
- hr = E_FAIL;
- }
-
- break;
-
- default:
- // For any other container type, don't know how to interpret the ids.
- if (m_HeapInfoNeeded & HMC_INFO_HEAP_ROOTS)
- {
- rootid = DiscoveredRoot(type, id1, NULL);
- if (rootid)
- ;
- else
- hr = E_OUTOFMEMORY;
- }
- break;
- }
-
- m_lastroottype = type;
- m_lastrootvmid1 = id1;
- m_lastrootvmid2 = id2;
- m_lastrootid = rootid;
-
- IncProgressIndicator();
-
- if (FAILED(hr) && type != C_BEGIN && type != C_HEAP)
- {
- Enter();
- {
- m_flags |= HMM_FL_INACCURATE;
- }
- Leave();
-
- hr = S_OK;
- }
-
- if (hr == S_OK)
- {
- if (!(m_HeapInfoNeeded & HMC_INFO_HEAP_ROOT_REFS) && type != C_HEAP)
- {
- hr = S_POSTPONE_REFERENCES;
- }
- }
-
- // TODO: allow user to cancel heap dump
-
- return hr;
- }
-
-
- STDMETHODIMP HeapMonitorManager::RootReferences (const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
- {
- if (m_HeapInfoNeeded & HMC_INFO_HEAP_ROOT_REFS)
- {
- RootReferencesEventInfo info;
- info.type = m_lastroottype;
- info.id1 = m_lastrootvmid1;
- info.id2 = m_lastrootvmid2;
- info.nrefs = nrefs;
- info.rgrefs = prefs;
- info.rgflags = pflags;
- info.rootid = m_lastrootid;
-
- for (unsigned i = 0; i < nrefs; i++)
- {
- ObjectID vmid = prefs[i];
- if (vmid)
- {
- m_gcinfo.nRootEdges++;
- m_gcinfo.rgcRootReferences[info.type - C_FIRST - 1]++;
-
- OBJID id = DiscoveredObject(vmid);
-
- Enter();
- {
- if (id)
- {
- id->flags |= OID_FL_REFERENCED_BY_ROOT;
- }
- else
- {
- m_flags |= HMM_FL_INACCURATE;
- }
- }
- Leave();
- }
- }
-
- if (m_lastrootid)
- {
- if (m_lastrootid->type == ID_ROOT)
- ((ROOTID)m_lastrootid)->flags |= RID_FL_HAS_REFERENCES;
- else if (m_lastrootid->type == ID_STACKFRAME)
- ((STACKID)m_lastrootid)->flags |= SID_FL_HAS_REFERENCES;
-
- m_rootrefs.AddRootReferences(m_lastrootid, nrefs, prefs);
-
- SendRootReferencesEvent(&info);
- }
- }
-
- // TODO: allow user to cancel heap dump
-
- return S_POSTPONE_REFERENCES;
- }
-
-
- STDMETHODIMP HeapMonitorManager::ObjectReferences (ObjectID vmid, DWORD flags, const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
- {
- ASSERT(m_HeapInfoNeeded & (HMC_INFO_HEAP_OBJECTS | HMC_INFO_HEAP_OBJECT_REFS));
-
- if (m_HeapInfoNeeded & HMC_INFO_HEAP_OBJECT_REFS)
- {
- BOOL fAnyStatusChange = FALSE;
-
- Enter();
- {
- OBJID id = (OBJID)LookupID(vmid);
-
- // See below...
- if (!(flags & JVM_OBJ_ALREADY_REPORTED))
- {
- if (!id)
- id = CreateOBJID(vmid);
- if (id)
- id->flags |= OID_FL_VISITED_BEFORE_REPORTED;
- }
-
- if (id)
- {
- // Indicate to ExpandObject not to hash references from this
- // object.
- id->flags |= OID_FL_EXPANDED;
- }
-
- for (unsigned i = 0; i < nrefs; i++)
- {
- ObjectID refvmid = prefs[i];
- if (refvmid)
- {
- m_gcinfo.nObjectEdges++;
-
- OBJID refid = (OBJID)LookupID(refvmid);
- if (refid)
- {
- DWORD oldflags = refid->flags;
- DWORD newflags = oldflags;
-
- newflags |= ID_FL_DISCOVERED;
-
- if ( (pflags[i] & JVM_OBJ_ALREADY_REPORTED)
- && !(oldflags & OID_FL_MULTIPLE_REFERENCES))
- {
- // If the object is visited before its first
- // reference is discovered, it will be marked
- // REPORTED for its first reference. We've
- // detected this special case above, this magic bit
- // means to treat this reference as the object's
- // first reference.
- //
- // This is a consequence of using
- // S_POSTPONE_REFERENCES to perform the heap dump.
- // If S_OK was returned, this would not be
- // necessary, since it would be impossible to
- // discover an object before at least one of its
- // referring objects is discovered.
-
- if (!(oldflags & OID_FL_VISITED_BEFORE_REPORTED))
- {
- newflags |= OID_FL_MULTIPLE_REFERENCES;
- m_gcinfo.nObjectsWithMultipleReferences++;
- }
- else
- {
- newflags &= ~OID_FL_VISITED_BEFORE_REPORTED;
- }
- }
-
- refid->flags = newflags;
-
- if (oldflags != newflags)
- fAnyStatusChange = TRUE;
- }
- else
- {
- if (pflags[i] & JVM_OBJ_ALREADY_REPORTED)
- {
- refid = CreateOBJID(refvmid);
- if (refid)
- {
- refid->flags |= ID_FL_DISCOVERED | OID_FL_MULTIPLE_REFERENCES;
-
- m_gcinfo.nObjectsWithMultipleReferences++;
-
- fAnyStatusChange = TRUE;
- }
- }
- }
- }
- }
- }
- Leave();
-
- if (fAnyStatusChange)
- {
- for (unsigned i = 0; i < nrefs; i++)
- {
- ObjectID refvmid = prefs[i];
- if (refvmid)
- {
- OBJID refid = (OBJID)LookupID(refvmid);
- if (refid)
- {
- SendObjectStatusChanged(refid);
- }
- }
- }
- }
- }
-
- if ( !(flags & JVM_OBJ_MORE_REFERENCES)
- && (m_HeapInfoNeeded & HMC_INFO_HEAP_OBJECTS))
- {
- m_gcinfo.nObjects++;
-
- DWORD size;
- HRESULT hrSize = m_vminfo->GetObjectSize(vmid, &size);
-
- if (hrSize == S_OK)
- m_gcinfo.cbObjects += size;
-
- CLASSID cls = NULL;
-
- ClassID clsvmid;
- if (m_vminfo->ObjectInformation(vmid, &clsvmid) == S_OK)
- cls = LookupClass(clsvmid);
-
- if (cls)
- {
- cls->liveinstances++;
-
- if (hrSize == S_OK)
- {
- cls->livesize += size;
- }
- else
- {
- Enter();
- {
- cls->flags |= CID_FL_INACCURATE;
- m_flags |= HMM_FL_INACCURATE;
- }
- Leave();
- }
-
- if (m_flags & HMM_FL_OBJECT_AGING)
- {
- DWORD age;
- if (m_vmheapmon->GetObjectAge(vmid, &age) == S_OK)
- {
- cls->agesum += age;
- }
- else
- {
- Enter();
- {
- cls->flags |= CID_FL_INACCURATE;
- m_flags |= HMM_FL_INACCURATE;
- }
- Leave();
- }
- }
- }
- else
- {
- Enter();
- {
- m_flags |= HMM_FL_INACCURATE;
- }
- Leave();
- }
- }
-
- // TODO: allow user to cancel heap dump
-
- // We're not concerned with context here, and a flat traversal of the
- // heap is more efficient for the VM.
- return S_POSTPONE_REFERENCES;
- }
-
-
- //------------------------------------------------------------------------
-
-
- HeapMonitorManager::HeapMonitorManager ()
- {
- m_RefCount = 1;
-
- InitializeCriticalSection(&m_cs);
- #ifdef DEBUG
- m_tidCriticalSectionOwner = INVALID_THREAD_ID;
- m_CriticalSectionEnterCount = 0;
- #endif // DEBUG
-
- m_flags = 0;
- m_hthd = NULL;
- m_tid = INVALID_THREAD_ID;
-
- m_hinst = NULL;
- m_hwnd = NULL;
- m_hmnu = NULL;
- m_hmnuWindow = NULL;
- m_mdi = NULL;
-
- m_ProgressIndicatorImages = NULL;
-
- m_hresumeevt = NULL;
-
- m_vminfo = NULL;
- m_vmheapmon = NULL;
-
- m_clients = NULL;
-
- m_EventMaskUnion = 0;
- m_InfoMaskUnion = 0;
- m_StoppedEventMaskUnion = 0;
- m_StoppedInfoMaskUnion = 0;
-
- m_IDMapChangeCount = 0;
-
- m_npkgents = 0;
- m_pkgents = NULL;
-
- m_rgpszContainerDescriptions = NULL;
- m_rgpszVerboseContainerDescriptions = NULL;
-
- m_iGC = 0;
- ZeroMemory(&m_gcinfo, sizeof(m_gcinfo));
-
- #ifdef DEBUG
- m_HeapDumpThreadId = INVALID_THREAD_ID;
- #endif // DEBUG
-
- m_trackedobjs = NULL;
-
- m_searchcb = NULL;
-
- m_heapwalks = NULL;
-
- EnterCriticalSection(&s_mgrlistcs);
- {
- m_next = s_mgrlist;
- s_mgrlist = this;
- }
- LeaveCriticalSection(&s_mgrlistcs);
-
- InterlockedIncrement((LONG*)&g_ModuleRefCount);
- }
-
-
- HeapMonitorManager::~HeapMonitorManager ()
- {
- ASSERT(!m_RefCount);
-
- InterlockedDecrement((LONG*)&g_ModuleRefCount);
-
- EnterCriticalSection(&s_mgrlistcs);
- {
- HeapMonitorManager **prev = &s_mgrlist;
- while (*prev != this)
- prev = &(*prev)->m_next;
- *prev = (*prev)->m_next;
- }
- LeaveCriticalSection(&s_mgrlistcs);
-
- if (m_flags & HMM_FL_ADDED_TRAY_ICON)
- RemoveTrayIcon();
-
- if (m_searchcb)
- m_searchcb->Release();
-
- TrackedObjectList *trkent = m_trackedobjs;
- while (trkent)
- {
- TrackedObjectList *trash = trkent;
- trkent = trkent->next;
- if (trash->tag)
- delete(trash->tag);
- delete(trash);
- }
-
- if (m_pkgents)
- {
- for (DWORD i = 0; i < m_npkgents; i++)
- {
- PkgTokenEntry *ent = &m_pkgents[i];
- if (!ent->name)
- break;
- delete(ent->name);
- }
- delete(m_pkgents);
- }
-
- ClientRecord *clientrec = m_clients;
- while (clientrec)
- {
- ClientRecord *next = clientrec->next;
- clientrec->client->Release();
- delete(clientrec);
- clientrec = next;
- }
-
- if (m_vmheapmon)
- m_vmheapmon->Release();
-
- if (m_vminfo)
- m_vminfo->Release();
-
- if (m_hresumeevt)
- CloseHandle(m_hresumeevt);
-
- if (m_hthd)
- PostThreadMessage(m_tid, WM_QUIT, 0, 0);
-
- if (m_ProgressIndicatorImages)
- ImageList_Destroy(m_ProgressIndicatorImages);
-
- DeletePtrArray((PVOID*)m_rgpszContainerDescriptions, C_LAST - C_FIRST - 1);
- DeletePtrArray((PVOID*)m_rgpszVerboseContainerDescriptions, C_LAST - C_FIRST - 1);
- }
-
-
- BOOL HeapMonitorManager::Initialize (HINSTANCE hInstance)
- {
- BOOL result;
-
- m_hinst = hInstance;
-
- result = (m_hresumeevt = CreateEvent(NULL, FALSE, FALSE, NULL)) != NULL;
-
- if (result)
- {
- result = (m_hthd = CreateThread(NULL, 0, &HeapMonitorManagerMessagePumpThread, this, 0, &m_tid)) != NULL;
- }
-
- return result;
- }
-
-
- VOID HeapMonitorManager::OnProcessAttach (HINSTANCE hinst)
- {
- InitializeCriticalSection(&s_mgrlistcs);
-
- s_htrayicon = (HICON)LoadImage(hinst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, 16, 16, 0/*LR_LOADTRANSPARENT*/);
- }
-
-
- VOID HeapMonitorManager::OnProcessDetach (HINSTANCE hinst)
- {
- for (HeapMonitorManager *list = s_mgrlist; list; list = list->m_next)
- {
- if (list->m_flags & HMM_FL_ADDED_TRAY_ICON)
- list->RemoveTrayIconWorker();
- }
-
- DeleteCriticalSection(&s_mgrlistcs);
- }
-
-
- //------------------------------------------------------------------------
-
-
- PSTR HeapMonitorManager::FetchIDFriendlyName (ID id)
- {
- PSTR pszname = id->name;
- if (!pszname && (id->type == ID_PACKAGE || id->type == ID_CLASS))
- {
- Enter();
- {
- pszname = id->name;
- if (!pszname)
- {
- PWSTR pwszname = NULL;
- BOOL fFreeName = FALSE;
-
- switch (id->type)
- {
- case ID_PACKAGE:
- {
- PkgTokenEntry *cur = m_pkgents;
- PkgTokenEntry *stop = cur + m_npkgents;
- while (cur < stop)
- {
- if (cur->id == id)
- {
- pwszname = cur->name;
- int len = wcslen(pwszname);
- PWCHAR pwch = pwszname+len-1;
- while (*pwch != '.' && *pwch != '/' && pwch > pwszname)
- pwch--;
- if (pwch > pwszname)
- pwch++;
- pwszname = pwch;
- break;
- }
- cur++;
- }
- }
- break;
-
- case ID_CLASS:
- {
- PSTR pclsname;
- if (SUCCEEDED(m_vminfo->ClassInformation(id->vmid, &pclsname, NULL, NULL, NULL, NULL)))
- {
- Utf8ToUnicode(pclsname, &pwszname);
- CoTaskMemFree(pclsname);
- }
- }
- break;
- }
-
- if (pwszname)
- {
- UnicodeToANSI(pwszname, -1, &pszname);
-
- id->name = pszname;
-
- if (fFreeName)
- delete(pwszname);
- }
- }
- }
- Leave();
- }
-
- return pszname;
- }
-
-
- //------------------------------------------------------------------------
-
-
- ULONG STDMETHODCALLTYPE HeapMonitorManager::AddRef (VOID)
- {
- ASSERT(m_RefCount && m_RefCount < ULONG_MAX);
-
- return InterlockedIncrement((LONG*)&m_RefCount);
- }
-
-
- ULONG STDMETHODCALLTYPE HeapMonitorManager::Release (VOID)
- {
- ASSERT(m_RefCount);
-
- ULONG NewRefCount = (ULONG)InterlockedDecrement((LONG*)&m_RefCount);
- if (NewRefCount)
- return NewRefCount;
-
- delete(this);
-
- return 0;
- }
-
-
- STDMETHODIMP HeapMonitorManager::QueryInterface (
- REFIID riid,
- PVOID *ppvObject)
- {
- HRESULT hr = S_OK;
-
- if ( riid == IID_IUnknown
- || riid == IID_IJavaEventMonitor
- || riid == IID_IJavaEventMonitor2)
- {
- *ppvObject = (IJavaEventMonitor2*)this;
- }
- else if (riid == IID_IHeapInfoCallback)
- {
- *ppvObject = (IHeapInfoCallback*)this;
- }
- else
- {
- *ppvObject = NULL;
- hr = E_NOINTERFACE;
- }
-
- if (hr == S_OK)
- AddRef();
-
- return(hr);
- }
-
-
- //------------------------------------------------------------------------
-
-
- IDWrapper::~IDWrapper ()
- {
- if (name)
- delete(name);
-
- if (type == ID_CLASS)
- {
- ClassIDWrapper *cls = (ClassIDWrapper*)this;
- if (cls->flds)
- delete(cls->flds);
- }
- else if (type == ID_OBJECT)
- {
- ASSERT(!(flags & ALL_OID_NONTRANSIENT_FLAGS));
- }
- }
-
-