home *** CD-ROM | disk | FTP | other *** search
- // main.cpp
- //
- // (C) Copyright 1995 - 1999 Microsoft Corporation. All rights reserved.
- //
-
- #include "project.hpp"
- #pragma hdrstop
-
- #include <jexefmt.h>
- #include <stdio.h>
-
- #include "jviewprf.hpp"
- #include "utils.hpp"
- #include "resource.h"
-
- extern HINSTANCE g_hInst;
-
- // dllmain.cpp
- VOID DisplayUsage ();
-
-
- //------------------------------------------------------------------------
-
-
- IJVIEWProfilerUtils *g_pJVIEW;
-
- ULONG g_nMethodsToHook = 0;
- PSTR *g_rgpszMethodsToHook = NULL;
- ULONG g_nClassesToHook = 0;
- PSTR *g_rgpszClassesToHook = NULL;
-
- ULONG g_SamplingFrequency = 100;
- BOOL g_fSamplingFrequencySpecified = FALSE;
-
- // Bitmask of OPT_XXX flags (jviewprf.hpp).
- DWORD g_ProfOptions = 0;
-
- EventMonitor *g_EventMonitor = NULL;
-
- // All profiling output is written here. This is either stdout or an output
- // file.
- HANDLE g_hOutput = INVALID_HANDLE_VALUE;
-
- // Filename specified via -prof:file=<filename>.
- PSTR g_pszOutputFileName = NULL;
-
- // Character width of whatever's on the other end of g_hOutput:
- // - For files, this is an arbitrarily bigger number, 120.
- // - For a console, this is the console's buffer width.
- // - For anything else (ex. redirected stdout), this is 80.
- // If OPT_TABLE (-prof:table) is set, this is 0, indicating that things should
- // not be spaced out.
- ULONG g_OutputWidth;
-
- // Set to TRUE if g_hOutput is a console.
- BOOL g_fOutputIsConsole = FALSE;
-
- // Indicates that WriteOutput should convert "\n" to "\r\n".
- #define g_fConvertNewlines (!g_fOutputIsConsole)
-
- // Set when FatalError is called. If EventMonitor::Initialize ends with a
- // failed HRESULT, and this is not set, FatalError is called with a default
- // "couldn't initialize" error message.
- BOOL g_fErrorMessageDisplayed = FALSE;
-
-
- //------------------------------------------------------------------------
-
-
- VOID FatalError (UINT id, ...)
- {
- va_list va;
-
- va_start(va, id);
- DisplayMessage(JDC_ERROR, id, va);
- va_end(va);
- }
-
-
- VOID Warning (UINT id, ...)
- {
- va_list va;
-
- va_start(va, id);
- DisplayMessage(JDC_WARNING, id, va);
- va_end(va);
- }
-
-
- VOID WriteOutput (PCSTR pcsz, int len)
- {
- if (!g_fConvertNewlines)
- {
- DWORD wrote;
- WriteFile(g_hOutput, pcsz, len, &wrote, NULL);
- return;
- }
-
- PCSTR stop = pcsz+len;
-
- for (;;)
- {
- int towrite;
-
- PCSTR nl = pcsz;
- while (nl < stop && *nl != '\n')
- nl++;
- if (nl < stop)
- towrite = nl - pcsz;
- else
- towrite = len;
-
- DWORD wrote;
- WriteFile(g_hOutput, pcsz, towrite, &wrote, NULL);
-
- pcsz += towrite;
- len -= towrite;
-
- if (nl < stop)
- {
- WriteFile(g_hOutput, "\r\n", 2, &wrote, NULL);
- pcsz++;
- len--;
- }
-
- if (!len)
- break;
- }
- }
-
-
- VOID WriteOutput (PCSTR pcsz)
- {
- int len = strlen(pcsz);
- WriteOutput(pcsz, len);
- }
-
-
- VOID WriteOutputW (PCWSTR pcwsz)
- {
- CHAR buf[2048];
- int len = WideCharToMultiByte(CP_ACP, 0, pcwsz, -1, buf, sizeof(buf)-1, NULL, NULL);
- if (len > 0)
- {
- if (buf[len-1] == '\0')
- len--;
- else
- buf[len] = '\0';
-
- if (g_fOutputIsConsole)
- CharToOem(buf, buf);
-
- WriteOutput(buf, len);
- }
- }
-
-
- VOID WriteOutputUtf8 (PCSTR pcszUtf8)
- {
- PSTR pszAnsi;
- if (Utf8ToAnsi(pcszUtf8, &pszAnsi))
- {
- if (!pszAnsi)
- {
- WriteOutput(pcszUtf8);
- }
- else
- {
- WriteOutput(pszAnsi);
- delete pszAnsi;
- }
- }
- }
-
-
- VOID WriteOutputFmt (PCSTR fmt, ...)
- {
- CHAR buf[WRITE_MAX_SIZE_NORM_FMT];
- va_list va;
- int len;
-
- va_start(va, fmt);
- len = g_pJVIEW->vsnprintf(buf, sizeof(buf), fmt, va);
- va_end(va);
-
- WriteOutput(buf, len);
- }
-
-
- VOID WriteOutputEx (DWORD flags, WriteOutputExArgs *pArgs, PCSTR pcsz)
- {
- PSTR pszAnsi = NULL;
-
- if (flags & WRITE_UTF8)
- {
- if (!Utf8ToAnsi(pcsz, &pszAnsi))
- return;
-
- if (pszAnsi)
- pcsz = pszAnsi;
-
- }
-
- ULONG len = strlen(pcsz);
-
- if ( g_OutputWidth
- && (flags & (WRITE_LEFT_JUSTIFIED | WRITE_CENTERED | WRITE_RIGHT_JUSTIFIED | WRITE_WRAP | WRITE_FIT)))
- {
- ULONG width = pArgs->Width;
-
- ULONG indent = width;
-
- if (flags & WRITE_FIT)
- {
- ULONG avail = g_OutputWidth - 1 - width;
- indent = pArgs->FixedSpaceUsed + (ULONG)(pArgs->PctFreeSpaceUsed*avail/100);
- width = (ULONG)(pArgs->PctFreeSpaceToUse*avail/100);
- indent += width;
- }
-
- if ((flags & WRITE_WRAP) && len > width)
- {
- WriteOutput(pcsz, len);
- WriteOutput("\n", 1);
-
- while (indent--)
- WriteOutput(" ", 1);
- }
- else
- {
- ULONG spc;
- if (width >= len)
- spc = width - len;
- else
- spc = 0;
-
- ULONG before = 0;
- ULONG after = spc;
-
- if (flags & WRITE_NEWLINE)
- after = 0;
-
- if (flags & WRITE_CENTERED)
- {
- before = spc/2;
- if (!(flags & WRITE_NEWLINE))
- after = spc-before;
- }
- else if (flags & WRITE_RIGHT_JUSTIFIED)
- {
- before = spc;
- after = 0;
- }
-
- while (before--)
- WriteOutput(" ", 1);
-
- WriteOutput(pcsz, len);
-
- while (after--)
- WriteOutput(" ", 1);
- }
- }
- else
- {
- WriteOutput(pcsz, len);
- }
-
- if (pszAnsi)
- delete pszAnsi;
-
- if (flags & WRITE_SPACE)
- WriteOutput(" ", 1);
- else if (flags & WRITE_NEWLINE)
- WriteOutput("\n", 1);
- }
-
-
- VOID WriteOutputFmtEx (DWORD flags, WriteOutputExArgs *pArgs, PCSTR fmt, ...)
- {
- CHAR buf[2048];
- va_list va;
-
- va_start(va, fmt);
-
- g_pJVIEW->vsnprintf(buf, sizeof(buf), fmt, va);
-
- va_end(va);
-
- WriteOutputEx(flags, pArgs, buf);
- }
-
-
- VOID WriteOutputFitString (DWORD flags, ULONG FixedWidth, ULONG PctFreeSpaceToUse, PCSTR pcsz)
- {
- WriteOutputExArgs args;
-
- args.Width = FixedWidth;
- args.PctFreeSpaceToUse = PctFreeSpaceToUse;
- args.PctFreeSpaceUsed = 0;
- args.FixedSpaceUsed = 0;
-
- WriteOutputEx(flags | WRITE_FIT, &args, pcsz);
- }
-
-
- VOID WriteOutputColumnULONG (DWORD flags, ULONG ColumnWidth, ULONG value)
- {
- CHAR buf[32];
-
- g_pJVIEW->snprintf(buf, sizeof(buf), "%u", value);
-
- WriteOutputColumnString(flags, ColumnWidth, buf);
- }
-
-
- VOID WriteOutputColumnString (DWORD flags, ULONG ColumnWidth, PCSTR pcsz)
- {
- WriteOutputExArgs args;
-
- args.Width = ColumnWidth;
-
- WriteOutputEx(flags, &args, pcsz);
- }
-
-
- VOID WriteOutputColumnFmt (DWORD flags, ULONG ColumnWidth, PCSTR fmt, ...)
- {
- CHAR buf[2048];
- va_list va;
-
- va_start(va, fmt);
-
- g_pJVIEW->vsnprintf(buf, sizeof(buf), fmt, va);
-
- va_end(va);
-
- WriteOutputColumnString(flags, ColumnWidth, buf);
- }
-
-
- VOID WriteCurrentTime (PCSTR prefix, PCSTR suffix)
- {
- SYSTEMTIME time;
- GetLocalTime(&time);
- WriteOutputFmt("%s%02u/%02u/%04u %02u:%02u:%02u%s",
- prefix,
- time.wMonth, time.wDay, time.wYear,
- time.wHour, time.wMinute, time.wSecond,
- suffix);
- }
-
-
- //------------------------------------------------------------------------
-
-
- STDMETHODIMP EventMonitor::JVIEWInitialize (IJVIEWProfilerUtils *putils)
- {
- if (!InitTimer())
- return E_FAIL;
-
- (g_pJVIEW = putils)->AddRef();
- return S_OK;
- }
-
-
- struct ParamInfo
- {
- PCSTR buf;
- PCSTR opts;
- BOOL failed;
- };
-
- BOOL EnableCallOption (DWORD mask, ParamInfo *pinfo)
- {
- if (pinfo->opts)
- {
- if ((g_ProfOptions & mask) != mask && (g_nMethodsToHook || g_nClassesToHook))
- {
- FatalError(IDS_MULTOPTSWITHCALLSPECS);
- return FALSE;
- }
-
- PCSTR p = pinfo->opts;
-
- if (*p != '\0')
- {
- for (;;)
- {
- PCSTR pstart = p;
- PCSTR pmethsep = NULL;
-
- BOOL fClass = TRUE;
- BOOL fParsing = FALSE;
- BOOL fWildcard = FALSE;
-
- CHAR ch;
-
- for (;;)
- {
- ch = *p;
-
- if (ch == ',' || ch == '+')
- break;
-
- if (ch <= 32)
- {
- if (ch == '\0')
- break;
-
- if (fParsing)
- {
- FatalError(IDS_INVALIDMETHODSIG, p);
- return FALSE;
- }
-
- pstart = p+1;
- }
- else
- {
- if (fParsing)
- {
- if (fWildcard)
- {
- FatalError(IDS_NONTRAILINGWILDCARD, p-1);
- return FALSE;
- }
-
- if (ch == '.')
- {
- if (fClass)
- {
- pmethsep = p;
- }
- }
- else if (ch == '(')
- {
- fClass = FALSE;
- }
- else if (ch == '*')
- {
- fWildcard = TRUE;
- }
- }
- else
- {
- if (ch == '.' || ch == '(' || ch == ';' || ch == '/' || ch == ')')
- {
- FatalError(IDS_INVALIDMETHODSIG, p);
- return FALSE;
- }
-
- if (ch == '*')
- {
- fWildcard = TRUE;
- }
-
- fParsing = TRUE;
- }
- }
-
- p++;
- }
-
- PCSTR pend = p;
-
- if (pstart < pend)
- {
- for (;;)
- {
- PSTR **ppArray;
- ULONG *pCount;
-
- if (fClass)
- {
- ppArray = &g_rgpszClassesToHook;
- pCount = &g_nClassesToHook;
- }
- else
- {
- ppArray = &g_rgpszMethodsToHook;
- pCount = &g_nMethodsToHook;
- }
-
- if (GrowStringArray(ppArray, pCount))
- {
- int len = pend - pstart;
- PSTR psz = new CHAR[len+1];
- CopyMemory(psz, pstart, len);
- psz[len] = '\0';
-
- (*ppArray)[*pCount - 1] = psz;
-
- if (fClass)
- pmethsep = pend;
-
- if (pmethsep)
- {
- pmethsep = psz + (pmethsep - pstart);
-
- while (psz < pmethsep)
- {
- if (*psz == '.')
- *psz = '/';
- psz++;
- }
- }
- }
-
- if (!fWildcard || !fClass)
- break;
-
- fClass = FALSE;
- pmethsep = NULL;
- }
- }
-
- if (ch == '\0')
- break;
-
- p++;
-
- if (ch == ',')
- break;
- }
- }
-
- pinfo->buf = p;
- }
-
- g_ProfOptions |= (OPT_PROF_CALLS | mask);
- return TRUE;
- }
-
-
- BOOL MatchParam (ParamInfo *pinfo, PCSTR param, int paramlen, BOOL fHasOptions)
- {
- if (pinfo->failed)
- return FALSE;
-
- PCSTR buf = pinfo->buf;
-
- if (memcmp(buf, param, paramlen) == 0)
- {
- PCSTR p = &buf[paramlen];
-
- for (;;)
- {
- CHAR endch = *p;
-
- if (endch == '\0')
- {
- pinfo->buf = p;
- pinfo->opts = NULL;
- return TRUE;
- }
-
- p++;
-
- if (endch == ',')
- {
- pinfo->buf = p;
- pinfo->opts = NULL;
- return TRUE;
- }
-
- if (endch <= 32)
- continue;
-
- if (endch == '=')
- {
- if (!fHasOptions)
- {
- FatalError(IDS_NOSETTINGSFOROPT, param);
- pinfo->failed = TRUE;
- break;
- }
-
- pinfo->opts = p;
- return TRUE;
- }
- }
- }
-
- return FALSE;
- }
-
- #define MatchParam(pinfo,s,fHasOptions) MatchParam(pinfo, s, sizeof(s)-1, fHasOptions)
-
-
- STDMETHODIMP EventMonitor::ParseParameters (PCSTR pcszParams)
- {
- const CHAR *p = pcszParams;
-
- ParamInfo info;
- info.failed = FALSE;
-
- for (;;)
- {
- CHAR ch = *p++;
-
- if (ch == '\0')
- break;
-
- if (ch <= 32)
- continue;
-
- info.buf = p-1;
-
- if (MatchParam(&info, "calls", TRUE)
- || MatchParam(&info, "calltimes", TRUE))
- {
- if (!EnableCallOption(OPT_CALL_TIMES, &info))
- goto failed;
- }
- else if (MatchParam(&info, "calltrace", TRUE))
- {
- if (!EnableCallOption(OPT_CALL_TRACE, &info))
- goto failed;
- }
- else if (MatchParam(&info, "callparams", TRUE))
- {
- if (!EnableCallOption(OPT_CALL_TRACE | OPT_CALL_TRACE_PARAMS, &info))
- goto failed;
- }
- else if (MatchParam(&info, "permethodalloc", FALSE))
- {
- g_ProfOptions |= (OPT_PROF_ALLOC | OPT_ALLOC_PER_METHOD);
- }
- else if (MatchParam(&info, "perclassalloc", FALSE))
- {
- g_ProfOptions |= (OPT_PROF_ALLOC | OPT_ALLOC_PER_CLASS);
- }
- else if (MatchParam(&info, "gc", FALSE))
- {
- g_ProfOptions |= (OPT_PROF_GC | OPT_GC_SUMMARY);
- }
- else if (MatchParam(&info, "heapdump", FALSE))
- {
- g_ProfOptions |= (OPT_PROF_GC | OPT_DUMP_HEAP);
- }
- else if (MatchParam(&info, "verbose", FALSE))
- {
- g_ProfOptions |= OPT_VERBOSE;
- }
- else if (MatchParam(&info, "file", TRUE))
- {
- if (!info.opts)
- {
- FatalError(IDS_MISSINGFILENAME);
- goto failed;
- }
-
- PCSTR comma = info.opts;
- while (*comma && *++comma != ',');
- PCSTR sep = comma;
-
- int len = sep - info.opts;
-
- g_pszOutputFileName = new CHAR[len+1];
- if (!g_pszOutputFileName)
- goto failed;
-
- CopyMemory(g_pszOutputFileName, info.opts, len);
- g_pszOutputFileName[len] = '\0';
-
- if (*comma)
- sep++;
- else
- break;
- info.buf = sep;
- }
- else if (MatchParam(&info, "sample", TRUE))
- {
- g_ProfOptions |= OPT_SAMPLE;
-
- if (info.opts)
- {
- if (g_fSamplingFrequencySpecified)
- {
- FatalError(IDS_MULTSAMPFREQ, info.opts);
- goto failed;
- }
-
- g_SamplingFrequency = atoi(info.opts);
- if (g_SamplingFrequency == 0)
- {
- FatalError(IDS_INVALIDSAMPFREQ, info.opts);
- goto failed;
- }
-
- g_fSamplingFrequencySpecified = TRUE;
-
- PCSTR comma = info.opts;
- while (*comma && *++comma != ',');
- if (*comma)
- info.buf = comma+1;
- else
- break;
- }
- }
- else if (MatchParam(&info, "table", FALSE))
- {
- g_ProfOptions |= OPT_TABLE;
- }
- else if ( MatchParam(&info, "?", FALSE)
- || MatchParam(&info, "help", FALSE))
- {
- DisplayUsage();
-
- return E_FAIL;
- }
- else
- {
- if (info.failed)
- goto failed;
-
- FatalError(IDS_INVALIDOPTION, info.buf);
- goto failed;
- }
-
- p = info.buf;
- }
-
- if ((g_ProfOptions & (OPT_PROF_CALLS | OPT_SAMPLE)) == (OPT_PROF_CALLS | OPT_SAMPLE))
- {
- FatalError(IDS_DONTSAMPLEANDHOOK);
-
- failed:
- return E_FAIL;
- }
-
- return S_OK;
- }
-
-
- //------------------------------------------------------------------------
-
-
- VOID EventMonitor::OnVMInitialization ()
- {
- m_fVMInitialized = TRUE;
-
- HMODULE hmodMSJava = GetModuleHandle("MSJAVA.DLL");
- if (hmodMSJava)
- {
- typedef BOOL __cdecl AddModuleResourceClassSourceProc (HMODULE hMod, DWORD dwResID);
- AddModuleResourceClassSourceProc *pfnAddModuleResourceClassSource;
-
- pfnAddModuleResourceClassSource = (AddModuleResourceClassSourceProc*)GetProcAddress(hmodMSJava, "AddModuleResourceClassSource");
- if (pfnAddModuleResourceClassSource)
- {
- (*pfnAddModuleResourceClassSource)(g_hInst, JEX_DEFAULT_CLASS_RESOURCE_ID);
- }
- }
-
- m_sampler.OnVMInitialization();
- }
-
-
- //------------------------------------------------------------------------
-
-
- ThreadRecord *EventMonitor::CreateCurrentThreadRecord ()
- {
- ThreadID vmid = NULL;
- DWORD tid = GetCurrentThreadId();
-
- if (m_monitor_info2)
- m_monitor_info2->GetCurrentThread(&vmid);
-
- ThreadRecord *pThread = GetThreadRecord(vmid, tid);
- if (pThread)
- TlsSetValue(m_threadtls, pThread);
-
- return pThread;
- }
-
-
- ThreadRecord *EventMonitor::GetThreadRecord (ThreadID vmid, DWORD tid)
- {
- ThreadRecord *ret = NULL;
-
- EnterCriticalSection(&m_ThreadEventCS);
- {
- for (ULONG i = 0; i < m_nthreads; i++)
- {
- ThreadRecord *prec = m_rgpthreads[i];
- if (prec->tid == tid)
- {
- prec->vmid = vmid;
- ret = prec;
- break;
- }
- }
-
- ret = CreateThreadRecord(vmid, tid);
- }
- LeaveCriticalSection(&m_ThreadEventCS);
-
- return ret;
- }
-
-
- ThreadRecord *EventMonitor::CreateThreadRecord (ThreadID vmid, DWORD tid)
- {
- ThreadRecord *pThread = NULL;
-
- if (m_nthreads >= m_maxthreads)
- {
- GrowPtrArray((PVOID**)&m_rgpthreads, &m_maxthreads, (m_maxthreads+1)*2);
- }
-
- if (m_nthreads < m_maxthreads)
- {
- pThread = new ThreadRecord();
- if (pThread)
- {
- ZeroMemory(pThread, sizeof(*pThread));
-
- pThread->vmid = vmid;
- pThread->tid = tid;
-
- m_rgpthreads[m_nthreads++] = pThread;
- }
- }
-
- return pThread;
- }
-
-
- //------------------------------------------------------------------------
-
-
- EventMonitor::EventMonitor ()
- {
- m_refcount = 1;
-
- m_monitor_info = NULL;
- m_monitor_info2 = NULL;
- m_monitor_info3 = NULL;
- m_monitor_info4 = NULL;
-
- m_VMRelease = VM_CURRENT;
-
- m_fVMInitialized = FALSE;
- m_fVMTerminated = FALSE;
-
- m_threadtls = TLS_OUT_OF_INDEXES;
- m_rgpthreads = NULL;
- m_nthreads = 0;
- m_maxthreads = 0;
- InitializeCriticalSection(&m_ThreadEventCS);
- }
-
-
- EventMonitor::~EventMonitor(void)
- {
- g_EventMonitor = NULL;
-
- m_callprof.Destruct();
- m_sampler.Destruct();
- m_calltracer.Destruct();
- m_allocprof.Destruct();
- m_gcprof.Destruct();
-
- if (m_monitor_info4)
- m_monitor_info4->Release();
-
- if (m_monitor_info3)
- m_monitor_info3->Release();
-
- if (m_monitor_info2)
- m_monitor_info2->Release();
-
- if (m_monitor_info)
- m_monitor_info->Release();
-
- if (m_rgpthreads)
- delete(m_rgpthreads);
- DeleteCriticalSection(&m_ThreadEventCS);
- if (m_threadtls != TLS_OUT_OF_INDEXES)
- TlsFree(m_threadtls);
- }
-
-
- VOID EventMonitor::ShutdownWorker (BOOL fNormal)
- {
- if (!g_EventMonitor)
- return;
-
- g_EventMonitor = NULL;
-
- if (!fNormal)
- WriteOutput("Process terminated.\n");
-
- WriteCurrentTime("End time: ", "\n");
-
- m_fVMTerminated = TRUE;
-
- m_callprof.SpewResults();
- m_allocprof.SpewResults();
- m_sampler.SpewSamplerResults();
-
- WriteOutput("--- End of profiler output ---\n");
-
- CloseHandle(g_hOutput);
- g_hOutput = INVALID_HANDLE_VALUE;
- }
-
-
- //------------------------------------------------------------------------
-
-
- ULONG EventMonitor::AddRef ()
- {
- return (ULONG)InterlockedIncrement((LPLONG)&m_refcount);
- }
-
-
- ULONG EventMonitor::Release ()
- {
- ULONG refcount = (ULONG)InterlockedDecrement((LPLONG)&m_refcount);
- if (!refcount)
- delete this;
- return refcount;
- }
-
-
- STDMETHODIMP EventMonitor::QueryInterface (REFIID riid, void ** ppv)
- {
- if ( riid == IID_IJavaEventMonitor
- || riid == IID_IJavaEventMonitor2
- || riid == IID_IUnknown)
- {
- *ppv = (IJavaEventMonitor2*)this;
- }
- else if (riid == IID_IObjectAllocationCallback)
- {
- *ppv = (IObjectAllocationCallback*)this;
- }
- else if (riid == IID_IJVIEWProfiler)
- {
- *ppv = (IJVIEWProfiler*)this;
- }
- else
- {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- AddRef();
- return S_OK;
- }
-
-
- //------------------------------------------------------------------------
-
-
- STDMETHODIMP EventMonitor::Initialize(LPCSTR pclass_file_name, IJavaEventMonitorIDInfo *pmonitor_info, DWORD java_flags, DWORD *prequested_events)
- {
- g_fErrorMessageDisplayed = FALSE;
-
- HRESULT hr = S_OK;
-
- (m_monitor_info = pmonitor_info)->AddRef();
-
- if (m_monitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo4, (void **)&m_monitor_info4) != S_OK)
- {
- m_monitor_info4 = NULL;
- m_VMRelease = VM_SDK31;
- }
-
- if (m_monitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo3, (void **)&m_monitor_info3) != S_OK)
- {
- m_monitor_info3 = NULL;
- m_VMRelease = VM_SDK30PR1;
- }
-
- if (m_monitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo2, (void **)&m_monitor_info2) != S_OK)
- {
- m_monitor_info2 = NULL;
- m_VMRelease = VM_IE40;
- }
-
- // These are the characteristics of the IE 4 VM, the first VM that
- // supported profiling. It did not support GetProfilingCapabilities.
-
- DWORD SupportedStates = ( JVM_STATE_INTERPRETER_ENABLED
- #ifdef _X86_
- | JVM_STATE_FAST_INTERPRETER_ENABLED
- | JVM_STATE_JIT_COMPILER_ENABLED
- #endif
- | JVM_STATE_DEBUGGER_ENABLED);
-
- // Note that JVM_MONITOR_SOURCE_LINE_EXECUTION,
- // JVM_MONITOR_MONITOR_OPERATIONS, and JVM_MONITOR_THREADS were defined in
- // the original IE4 jevmon.idl, but they were not fully supported by that
- // VM.
-
- DWORD SupportedEventCategories = ( JVM_MONITOR_CLASS_LOADS
- | JVM_MONITOR_METHOD_CALLS
- | JVM_MONITOR_JIT_COMPILATION
- | JVM_MONITOR_BYTE_CODE_EXECUTION
- | JVM_MONITOR_EXCEPTIONS
- | JVM_MONITOR_GARBAGE_COLLECTIONS);
-
- JAVA_EXECUTION_MODEL LastSupportedExecModel = JVM_EXECUTION_COM;
-
- JVM_EVENT_TYPE LastSupportedEventType = JVM_EVENT_TYPE_SHUTDOWN;
-
- // IJavaEventMonitor2 was not supported by the IE4 VM.
- JVM_EVENT_TYPE2 LastSupportedEventType2 = (JVM_EVENT_TYPE2)-1;
-
- if (m_monitor_info2 != NULL)
- {
- LPSTR pszClassPath;
- hr = m_monitor_info2->GetClassPath(&pszClassPath);
- if (hr == S_OK)
- {
- WriteOutputFmt("class path: %s\n", pszClassPath);
-
- CoTaskMemFree(pszClassPath);
- }
-
- hr = m_monitor_info2->GetProfilingCapabilities(
- &SupportedStates,
- &SupportedEventCategories,
- &LastSupportedExecModel,
- &LastSupportedEventType,
- &LastSupportedEventType2);
- }
-
-
- if (!(g_ProfOptions & ~OPT_NON_EVENT_OPTIONS))
- {
- g_ProfOptions |= OPT_DEFAULT_OPTIONS;
- }
-
-
- if (hr == S_OK)
- {
- if (g_pszOutputFileName)
- {
- g_hOutput = CreateFile(
- g_pszOutputFileName,
- GENERIC_WRITE,
- FILE_SHARE_READ,
- NULL,
- OPEN_ALWAYS,
- 0,
- NULL);
- if (g_hOutput == INVALID_HANDLE_VALUE)
- {
- FatalError(IDS_CANTAPPEND, g_pszOutputFileName);
- hr = HRESULT_FROM_WIN32(GetLastError());
- }
- else
- {
- LONG dwSizeHi = 0;
- LONG dwSizeLo = SetFilePointer(g_hOutput, 0, &dwSizeHi, FILE_END);
- }
-
- if (g_ProfOptions & OPT_TABLE)
- {
- g_OutputWidth = 0;
- }
- else
- {
- g_OutputWidth = 120;
- }
- }
- else
- {
- g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-
- if (g_ProfOptions & OPT_TABLE)
- {
- g_OutputWidth = 0;
- }
- else
- {
- CONSOLE_SCREEN_BUFFER_INFO coninfo;
- if (GetConsoleScreenBufferInfo(g_hOutput, &coninfo))
- {
- g_OutputWidth = coninfo.dwSize.X;
- g_fOutputIsConsole = TRUE;
- }
- else
- {
- g_OutputWidth = 80;
- }
- }
- }
- }
-
-
- if (hr == S_OK)
- {
- BOOL first = TRUE;
-
- WriteOutput("VM state:");
-
- #define SPEWSTATE(flag,descr) \
- if ((java_flags & (flag)) != 0) \
- { \
- if (!first) \
- WriteOutput(","); \
- else \
- first = FALSE; \
- WriteOutput(" " descr); \
- }
-
- SPEWSTATE(JVM_STATE_INTERPRETER_ENABLED, "Interpreter loop");
- SPEWSTATE(JVM_STATE_FAST_INTERPRETER_ENABLED, "Fast interpreter loop");
- SPEWSTATE(JVM_STATE_JIT_COMPILER_ENABLED, "JIT compiler");
- SPEWSTATE(JVM_STATE_DEBUGGER_ENABLED, "Debugging");
-
- #undef SPEWSTATE
-
- WriteOutput("\n");
- }
-
-
- if (hr == S_OK)
- {
- hr = m_gcprof.Initialize(this);
- }
-
- if (hr == S_OK)
- {
- hr = m_callprof.Initialize(this);
- }
-
- if (hr == S_OK)
- {
- hr = m_calltracer.Initialize(this);
- }
-
- if (hr == S_OK)
- {
- hr = m_allocprof.Initialize(this);
- }
-
- if (hr == S_OK)
- {
- hr = m_sampler.Initialize(this, &m_callprof);
- }
-
-
- // Install an allocation hook if any form of allocation profiling is enabled.
-
- if (hr == S_OK)
- {
- if (g_ProfOptions & OPT_PROF_ALLOC)
- {
- UINT idError = IDS_CANTHOOKALLOCS;
-
- IJavaHeapMonitor *pheapmon;
- hr = pmonitor_info->QueryInterface(IID_IJavaHeapMonitor, (PVOID*)&pheapmon);
- if (hr == S_OK)
- {
- IObjectAllocationCallback *alloccb;
- hr = QueryInterface(IID_IObjectAllocationCallback, (PVOID*)&alloccb);
- if (hr == S_OK)
- {
- hr = pheapmon->NotifyOnObjectAllocations(alloccb);
-
- alloccb->Release();
- }
- }
- else
- {
- idError = IDS_ALLOCHOOKNOTSUP;
- }
-
- if (hr != S_OK)
- {
- FatalError(idError);
- }
- }
- }
-
-
- // Determine which events are needed based on the specified profiling options.
-
- if (hr == S_OK)
- {
- DWORD events = 0;
-
- if (g_ProfOptions & OPT_PROF_CALLS)
- {
- if (LastSupportedEventType2 < JVM_EVENT_TYPE2_EXCEPTION_THROWN)
- {
- // TODO: The call profiling implementation here depends in
- // IJavaEventMonitor2::MethodExit2 and
- // JVM_EVENT_TYPE2_EXCEPTION_THROWN. To implement this for the
- // IE4 VM, the stack must be mirrored to know the method that
- // each call is returning to. MethodExit only provides the
- // StackID.
-
- FatalError(IDS_CALLPROFNOTIMPFORIE4VM);
- hr = E_FAIL;
- }
-
- if (hr == S_OK)
- {
- if (g_nClassesToHook + g_nMethodsToHook)
- {
- events |= (JVM_MONITOR_CLASS_LOADS | JVM_MONITOR_SPECIFIC_METHOD_CALLS);
-
- if (!(SupportedEventCategories & JVM_MONITOR_SPECIFIC_METHOD_CALLS) || !m_monitor_info3)
- {
- FatalError(IDS_SPECMETHODSNOTSUP);
- hr = E_FAIL;
- }
- }
- else
- {
- events |= JVM_MONITOR_METHOD_CALLS;
- }
-
- events |= (JVM_MONITOR_THREADS | JVM_MONITOR_EXCEPTIONS);
- }
- }
-
- if (hr == S_OK)
- {
- if (g_ProfOptions & OPT_PROF_ALLOC)
- {
- events |= JVM_MONITOR_GARBAGE_COLLECTIONS;
-
- if (g_ProfOptions & OPT_ALLOC_PER_METHOD)
- {
- if (LastSupportedEventType2 < JVM_EVENT_TYPE2_STACK_TRACE)
- {
- FatalError(IDS_STACKTRACENOTSUP);
- hr = E_FAIL;
- }
-
- events |= JVM_MONITOR_THREADS;
- }
- }
- }
-
- if (hr == S_OK)
- {
- if (g_ProfOptions & OPT_PROF_GC)
- {
- events |= JVM_MONITOR_GARBAGE_COLLECTIONS;
- }
- }
-
- if (hr == S_OK)
- {
- if (g_ProfOptions & OPT_SAMPLE)
- {
- if (!(SupportedEventCategories & JVM_MONITOR_SAMPLING))
- {
- FatalError(IDS_SAMPLINGNOTSUP);
- hr = E_FAIL;
- }
-
- events |= (JVM_MONITOR_THREADS | JVM_MONITOR_SAMPLING);
-
- if (LastSupportedEventType2 < JVM_EVENT_TYPE2_INITIALIZED)
- {
- // If this event is not supported, then presumably
- // IJavaEventMonitorIDInfo2::SampleThreadLocation will
- // simply fail until the VM is fully initialized.
-
- OnVMInitialization();
- }
-
- // We won't bother to check for JVM_EVENT_TYPE_SHUTDOWN - if
- // it's not supported, VM apis must already be safe to call
- // during shutdown. Also, the VM cannot reliably dispatch
- // this event, so shutdown code must already assume that this
- // event may never be received.
- }
- }
-
-
- if (g_ProfOptions & OPT_VERBOSE)
- {
- events |= JVM_MONITOR_CLASS_LOADS
- | JVM_MONITOR_EXCEPTIONS
- | JVM_MONITOR_GARBAGE_COLLECTIONS
- | JVM_MONITOR_THREADS;
-
- events &= SupportedEventCategories;
- }
-
-
- if (hr == S_OK && (SupportedEventCategories & events) != events)
- {
- FatalError(IDS_OPTNOTSUP);
- hr = E_FAIL;
- }
-
-
- if (hr == S_OK)
- {
- if (events & JVM_MONITOR_THREADS)
- {
- m_threadtls = TlsAlloc();
- if (m_threadtls == TLS_OUT_OF_INDEXES)
- hr = E_OUTOFMEMORY;
- }
- }
-
- if (hr == S_OK)
- {
- *prequested_events = events;
-
- if (m_monitor_info4)
- {
- // Enabling these two options allows the VM to substantially
- // reduce method call event overhead.
-
- DWORD initopts = JVM_INIT_OPT_GC_SAFE_METHOD_CALLS
- | JVM_INIT_OPT_WONT_TOGGLE_METHOD_CALL_EVENTS;
-
- // Enabling these two removes slightly more.
-
- initopts |= JVM_INIT_OPT_FP_SAFE_METHOD_CALLS;
-
- if (!(g_ProfOptions & OPT_CALL_TRACE_PARAMS))
- initopts |= JVM_INIT_OPT_RETURN_VALUE_NOT_NEEDED;
-
- m_monitor_info4->SetMonitorInitializationOptions(initopts);
- }
- }
- }
-
-
- if (g_ProfOptions & OPT_VERBOSE)
- {
- // TODO: spew event mask
- }
-
-
- if (hr == S_OK)
- {
- g_EventMonitor = this;
-
- WriteCurrentTime("Start time: ", "\n");
- }
- else
- {
- // Returning a non-S_OK value detaches the profiler. If some path
- // through here didn't indicate a failure to the user, this is our
- // last chance to do so.
-
- if (!g_fErrorMessageDisplayed)
- FatalError(IDS_CANTPROFILE);
- }
-
-
- return(hr);
- }
-
-
- STDMETHODIMP EventMonitor::NotifyEvent(JVM_EVENT_TYPE event, UniqueID event_id)
- {
- HRESULT hr;
-
- switch (event)
- {
- ThreadRecord *pThread;
-
- case JVM_EVENT_TYPE_THREAD_CREATE: // A Java threadID is being created (ThreadID created)
-
- pThread = NULL;
-
- if (m_monitor_info2)
- {
- DWORD tid = 0;
- if (SUCCEEDED(m_monitor_info2->ThreadInformation((ThreadID)event_id, &tid)))
- pThread = GetThreadRecord((ThreadID)event_id, tid);
- }
-
- if (g_ProfOptions & OPT_VERBOSE)
- {
- if (pThread)
- WriteOutputFmt("Thread %x created\n", pThread->tid);
- else
- WriteOutput("Thread created\n");
- }
-
- break;
-
- case JVM_EVENT_TYPE_THREAD_DESTROY: // A Java threadID is being destroyed (ThreadID destroyed)
-
- pThread = NULL;
-
- EnterCriticalSection(&m_ThreadEventCS);
- {
- ThreadID vmid = (ThreadID)event_id;
- DWORD tid = 0;
-
- if (m_monitor_info2)
- m_monitor_info2->ThreadInformation(vmid, &tid);
-
- if (m_rgpthreads)
- {
- unsigned i;
- for (i = 0; i < m_nthreads; i++)
- {
- pThread = m_rgpthreads[i];
- if (pThread->vmid == vmid || pThread->tid == tid)
- {
- m_nthreads--;
- m_rgpthreads[i] = m_rgpthreads[m_nthreads];
- break;
- }
- }
- }
- }
- LeaveCriticalSection(&m_ThreadEventCS);
-
- if (g_ProfOptions & OPT_VERBOSE)
- {
- if (pThread)
- WriteOutputFmt("Thread %x destroyed\n", pThread->tid);
- else
- WriteOutput("Thread destroyed\n");
- }
-
- if (pThread)
- delete pThread;
-
- break;
-
- case JVM_EVENT_TYPE_CLASS_LOAD_STARTED: // A class is being loaded (PSTR)
- if (g_ProfOptions & OPT_VERBOSE)
- WriteOutputFmt("Loading class %s...\n", (PCSTR)event_id);
- break;
-
- case JVM_EVENT_TYPE_CLASS_LOAD_FAILED: // A class failed to load (PSTR).
- if (g_ProfOptions & OPT_VERBOSE)
- WriteOutputFmt("Failed to load class %s.\n", (PCSTR)event_id);
- break;
-
- case JVM_EVENT_TYPE_CLASS_LOAD_FINISHED: // A class has been loaded (ClassID)
-
- if (m_VMRelease > VM_IE40)
- {
- PSTR pszClassUtf8 = NULL;
- int ncMethods;
- MethodID *pmethodid = NULL;
-
- BOOL fNeedClassName = (g_ProfOptions & OPT_VERBOSE) || g_nClassesToHook;
-
- hr = m_monitor_info->ClassInformation(
- (ClassID)event_id,
- fNeedClassName ? &pszClassUtf8 : NULL,
- NULL,
- &ncMethods,
- g_nMethodsToHook ? &pmethodid : NULL,
- NULL);
-
- if (SUCCEEDED(hr))
- {
- if (pszClassUtf8)
- {
- PSTR pszClass = pszClassUtf8;
- PSTR pszClassAnsi;
- if (Utf8ToAnsi(pszClassUtf8, &pszClassAnsi))
- {
- if (pszClassAnsi)
- pszClass = pszClassAnsi;
-
- if (g_ProfOptions & OPT_VERBOSE)
- WriteOutputFmt("Class %s successfully loaded.\n", pszClass);
-
- if (g_nClassesToHook)
- {
- ULONG iPattern;
-
- for (iPattern = 0; iPattern < g_nClassesToHook; iPattern++)
- {
- if (match(g_rgpszClassesToHook[iPattern], pszClass))
- {
- m_monitor_info3->EnableMethodCallEvents(
- (ClassID)event_id,
- JVM_ID_CLASS,
- JVM_PERMIT_METHOD_CALL_EVENTS);
- ncMethods = 0;
- break;
- }
- }
- }
-
- if (pszClassAnsi)
- delete pszClassAnsi;
- }
-
- CoTaskMemFree(pszClassUtf8);
- }
-
- if (pmethodid)
- {
- int iMethod;
-
- for (iMethod = 0; iMethod < ncMethods; iMethod++)
- {
- PSTR pszMethodUtf8;
- if (SUCCEEDED(m_monitor_info->MethodInformation(pmethodid[iMethod], &pszMethodUtf8, NULL, NULL, NULL, NULL)))
- {
- PSTR pszMethod = pszMethodUtf8;
- PSTR pszMethodAnsi;
- if (Utf8ToAnsi(pszMethodUtf8, &pszMethodAnsi))
- {
- if (pszMethodAnsi)
- pszMethod = pszMethodAnsi;
-
- ULONG iPattern;
-
- for (iPattern = 0; iPattern < g_nMethodsToHook; iPattern++)
- {
- if (match(g_rgpszMethodsToHook[iPattern], pszMethod))
- {
- m_monitor_info3->EnableMethodCallEvents(
- pmethodid[iMethod],
- JVM_ID_METHOD,
- JVM_PERMIT_METHOD_CALL_EVENTS);
- break;
- }
- }
-
- if (pszMethodAnsi)
- delete pszMethodAnsi;
- }
-
- CoTaskMemFree(pszMethodUtf8);
- }
- }
-
- CoTaskMemFree(pmethodid);
- }
- }
- }
- else
- {
- // Sorry. The IE4 VM provided a PCSTR instead of a ClassID.
-
- if (g_ProfOptions & OPT_VERBOSE)
- WriteOutputFmt("Class %s successfully loaded.\n", (PCSTR)event_id);
- }
-
- break;
-
- case JVM_EVENT_TYPE_CLASS_UNLOAD: // A class has been unloaded (ClassID)
- {
- if (m_VMRelease > VM_IE40)
- {
- // BUGBUG: remove any references to the unloading class, cache any info needed
-
- PSTR pszClassUtf8;
-
- hr = m_monitor_info->ClassInformation(event_id, &pszClassUtf8, NULL, NULL, NULL, NULL);
-
- if (hr == S_OK)
- {
- if (g_ProfOptions & OPT_VERBOSE)
- {
- WriteOutput("Class ");
- WriteOutputUtf8(pszClassUtf8);
- WriteOutput(" unloaded.\n");
- }
-
- CoTaskMemFree(pszClassUtf8);
- }
- }
- else
- {
- // Sorry. The IE4 VM provided a PCSTR instead of a ClassID.
-
- if (g_ProfOptions & OPT_VERBOSE)
- WriteOutputFmt("Class %s unloaded.\n", (PCSTR)event_id);
- }
-
- break;
- }
-
- case JVM_EVENT_TYPE_GC_STARTED: // The garbage collector started (no ID)
- m_gcprof.GCStarted();
- break;
-
- case JVM_EVENT_TYPE_GC_FINISHED: // The garbage collector stopped (no ID)
- if (g_ProfOptions & OPT_VERBOSE)
- WriteOutput("Garbage collection occurred.\n");
- m_gcprof.GCFinished();
- m_allocprof.GCOccurred();
- break;
-
- case JVM_EVENT_TYPE_SHUTDOWN: // Program exiting (no ID).
- ShutdownWorker(TRUE);
- break;
-
- default:
- // What is this?
- break;
- }
-
- return S_OK;
- }
-
-
- STDMETHODIMP EventMonitor::MethodEntry (MethodID method_id, StackID stack_id)
- {
- ThreadRecord *pThread = GetCurrentThreadRecord();
- if (pThread)
- {
- m_calltracer.OnEnterMethod(pThread, method_id, stack_id);
-
- m_callprof.EnterMethod(pThread, method_id);
- }
-
- return S_OK;
- }
-
-
- STDMETHODIMP EventMonitor::MethodExit(StackID stack_id)
- {
- ThreadRecord *pThread = GetCurrentThreadRecord();
- if (pThread)
- {
- m_callprof.ExitMethod(pThread);
-
- m_calltracer.OnMethodExit(pThread, NULL, stack_id);
- }
-
- return S_OK;
- }
-
-
- STDMETHODIMP EventMonitor::ExecuteByteCode(MethodID method_id, BYTE_CODE *pbyte_code, DWORD byte_code_offset)
- {
- return S_OK;
- }
-
-
- STDMETHODIMP EventMonitor::ExecuteSourceLine(MethodID method_id, DWORD line_number)
- {
- return(S_OK);
- }
-
-
- STDMETHODIMP EventMonitor::NotifyEvent2(JVM_EVENT_TYPE2 event2, UniqueID first_event_id, UniqueID second_event_id)
- {
- HRESULT hr = S_OK;
-
- switch (event2)
- {
- ThreadRecord *pThread;
-
- // A thread's name has been set. ID1 is ThreadID. ID2 is pointer to Unicode string thread name.
- case JVM_EVENT_TYPE2_THREAD_SET_NAME:
- if (g_ProfOptions & OPT_VERBOSE)
- {
- ThreadID vmid = (ThreadID)first_event_id;
- PCWSTR newname = (PCWSTR)second_event_id;
-
- if (m_monitor_info2)
- {
- DWORD tid;
- if (SUCCEEDED(m_monitor_info2->ThreadInformation(vmid, &tid)))
- {
- WriteOutputFmt("Thread %x's name changed to \"", tid);
- WriteOutputW(newname);
- WriteOutput("\".\n");
- }
- }
- }
- break;
-
- // An exception is about to be thrown. ID1 is the ClassID of the exception, ID2 is the ObjectID of the exception.
- case JVM_EVENT_TYPE2_EXCEPTION_THROWN:
- pThread = GetCurrentThreadRecord();
- if (pThread)
- m_callprof.ExceptionThrown(pThread);
-
- if (g_ProfOptions & OPT_VERBOSE)
- {
- PSTR pszExceptionUtf8;
- if (SUCCEEDED(m_monitor_info->ClassInformation((ClassID)first_event_id, &pszExceptionUtf8, NULL, NULL, NULL, NULL)))
- {
- WriteOutput("Exception ");
- WriteOutputUtf8(pszExceptionUtf8);
- WriteOutput(" \n");
-
- CoTaskMemFree(pszExceptionUtf8);
- }
- }
-
- break;
-
- // An exception occurred. ID1 is MethodID, ID2 is StackID. The exception handler will be executed in MethodID/StackID's stack frame.
- case JVM_EVENT_TYPE2_EXCEPTION_OCCURRED:
- pThread = GetCurrentThreadRecord();
- if (pThread)
- m_callprof.ResumeMethod(pThread, (MethodID)first_event_id);
- break;
-
- // Callback from GetStackTrace. ID1 is MethodID, ID2 is StackID.
- case JVM_EVENT_TYPE2_STACK_TRACE:
- pThread = GetCurrentThreadRecord();
- pThread->allocdata.idCreatingMethod = (MethodID)first_event_id;
- hr = S_FALSE;
- break;
-
- // The vm has fully initialized.
- case JVM_EVENT_TYPE2_INITIALIZED:
- OnVMInitialization();
- break;
-
- // All event monitors have initialized. ID1 is the number of event monitors
- // attached to the VM. ID2 is a bitmask of JAVA_EVENT_CATEGORY, indicating the
- // maximum possible set of events that may be enabled by all attached profilers.
- case JVM_EVENT_TYPE2_MONITORS_INITIALIZED:
-
- unsigned nmonitors;
- nmonitors = (unsigned)first_event_id;
-
- if (nmonitors > 1)
- WriteOutputFmt("%u other profilers are attached.\n", nmonitors-1);
-
- if (g_ProfOptions & OPT_VERBOSE)
- {
- DWORD possible_events = (DWORD)second_event_id;
-
- #if 0
- Spew(SPEW_REG, "%u monitors, possible events:", nmonitors);
- SpewCategories(SPEW_REG, possible_events);
- Spew(SPEW_REG, "\n");
- #endif
-
- }
-
- if (m_monitor_info4 != NULL)
- {
- DWORD initopts;
- hr = m_monitor_info4->GetFinalInitializationOptions(&initopts);
- if (hr == S_OK)
- {
- #if 0
- Spew(SPEW_REG, "final initialization options:");
- SpewInitOptions(SPEW_REG, initopts);
- Spew(SPEW_REG, "\n");
- #endif
- }
- }
-
- break;
- }
-
- return(hr);
- }
-
-
- STDMETHODIMP EventMonitor::MethodExit2(MethodID method_id, StackID stack_id)
- {
- ThreadRecord *pThread = GetCurrentThreadRecord();
- if (pThread)
- {
- m_callprof.ExitMethod(pThread);
-
- m_calltracer.OnMethodExit(pThread, method_id, stack_id);
-
- m_callprof.ResumeMethod(pThread, method_id);
- }
-
- return S_OK;
- }
-
-
- STDMETHODIMP EventMonitor::GetPossibleEventCategories (DWORD *ppossible_events)
- {
- // We don't toggle any events.
- return m_monitor_info->GetEventMask(ppossible_events);
- }
-
-
- //------------------------------------------------------------------------
-
-
- STDMETHODIMP EventMonitor::OnObjectAllocated (ObjectID idObject, ClassID idType)
- {
- DWORD size = 0;
- if (m_monitor_info2 != NULL)
- if (m_monitor_info2->GetObjectSize(idObject, &size) != S_OK)
- size = 0;
-
- MethodID idCreatingMethod = NULL;
- if (g_ProfOptions & OPT_ALLOC_PER_METHOD)
- {
- ThreadRecord *pThread = GetCurrentThreadRecord();
- if (pThread != NULL)
- {
- if (g_ProfOptions & OPT_PROF_CALLS)
- {
- // If there is no current entry, then the allocation occurred
- // in native code. (For example, the VM performs allocations
- // during initialization, before any methods are called.)
- CallProfiler::CallProfilerEntry *pent = pThread->calldata.pentCurMethod;
- if (pent)
- idCreatingMethod = pent->id;
- }
- else
- {
- pThread->allocdata.idCreatingMethod = NULL;
- m_monitor_info2->GetStackTrace(NULL);
- idCreatingMethod = pThread->allocdata.idCreatingMethod;
- }
- }
- }
-
- m_allocprof.InstanceCreated(idType, size, idCreatingMethod);
-
- return S_OK;
- }
-
-