home *** CD-ROM | disk | FTP | other *** search
/ Enter 1999 November / ENTER11_1.bin / WARSZTAT / SDKJava32.exe / data1.cab / fg_Samples / Samples / Profiler / jviewprf / main.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-17  |  51.1 KB  |  1,887 lines

  1. // main.cpp
  2. //
  3. // (C) Copyright 1995 - 1999 Microsoft Corporation.  All rights reserved.
  4. //
  5.  
  6. #include "project.hpp"
  7. #pragma hdrstop
  8.  
  9. #include <jexefmt.h>
  10. #include <stdio.h>
  11.  
  12. #include "jviewprf.hpp"
  13. #include "utils.hpp"
  14. #include "resource.h"
  15.  
  16.  
  17. //------------------------------------------------------------------------
  18.  
  19.  
  20. IJVIEWProfilerUtils *g_pJVIEW;
  21.  
  22. ULONG g_nMethodsToHook = 0;
  23. PSTR *g_rgpszMethodsToHook = NULL;
  24. ULONG g_nClassesToHook = 0;
  25. PSTR *g_rgpszClassesToHook = NULL;
  26.  
  27. ULONG g_SamplingFrequency = 100;
  28. BOOL g_fSamplingFrequencySpecified = FALSE;
  29.  
  30. // Bitmask of OPT_XXX flags (jviewprf.hpp).
  31. DWORD g_ProfOptions = 0;
  32.  
  33. EventMonitor *g_EventMonitor = NULL;
  34.  
  35. // All profiling output is written here.  This is either stdout or an output
  36. // file.
  37. HANDLE g_hOutput = INVALID_HANDLE_VALUE;
  38.  
  39. // Filename specified via -prof:file=<filename>.
  40. PSTR g_pszOutputFileName = NULL;
  41.  
  42. // Character width of whatever's on the other end of g_hOutput:
  43. // - For files, this is an arbitrarily bigger number, 120.
  44. // - For a console, this is the console's buffer width.
  45. // - For anything else (ex. redirected stdout), this is 80.
  46. // If OPT_TABLE (-prof:table) is set, this is 0, indicating that things should
  47. // not be spaced out.
  48. ULONG g_OutputWidth;
  49.  
  50. // Set to TRUE if g_hOutput is a console.
  51. BOOL g_fOutputIsConsole = FALSE;
  52.  
  53. // Indicates that WriteOutput should convert "\n" to "\r\n".
  54. #define g_fConvertNewlines (!g_fOutputIsConsole)
  55.  
  56. // Set when FatalError is called.  If EventMonitor::Initialize ends with a
  57. // failed HRESULT, and this is not set, FatalError is called with a default
  58. // "couldn't initialize" error message.
  59. BOOL g_fErrorMessageDisplayed = FALSE;
  60.  
  61.  
  62. //------------------------------------------------------------------------
  63.  
  64.  
  65. HINSTANCE g_hInst = NULL;
  66.  
  67.  
  68. BOOL WINAPI DllMain (HINSTANCE hInst, ULONG reason, LPVOID reserved)
  69. {
  70.     g_hInst = hInst;
  71.  
  72.     switch (reason)
  73.     {
  74.     case DLL_PROCESS_ATTACH:
  75.         DisableThreadLibraryCalls(hInst);
  76.         break;
  77.  
  78.     case DLL_PROCESS_DETACH:
  79.         if (g_EventMonitor)
  80.             g_EventMonitor->ShutdownWorker(FALSE);
  81.         break;
  82.     }
  83.  
  84.     return TRUE;
  85. }
  86.  
  87.  
  88. //------------------------------------------------------------------------
  89.  
  90.  
  91. IJVIEWProfiler * __stdcall JVIEWPRF_CreateProfilerProcName ()
  92. {
  93.     return new EventMonitor();
  94. }
  95.  
  96.  
  97. //------------------------------------------------------------------------
  98.  
  99.  
  100. VOID DisplayMessage (BOOL fError, UINT id, va_list va)
  101. {
  102.     CHAR fmt[1024];
  103.  
  104.     if (g_pJVIEW->LoadResourceString(g_hInst, id, fmt, sizeof(fmt)))
  105.     {
  106.         CHAR buf[1024];
  107.  
  108.         g_pJVIEW->vsnprintf(buf, sizeof(buf), fmt, va);
  109.  
  110.         if (g_pJVIEW->DisplayString(JDC_ERROR, buf) && fError)
  111.             g_fErrorMessageDisplayed = TRUE;
  112.     }
  113. }
  114.  
  115.  
  116. VOID FatalError (UINT id, ...)
  117. {
  118.     va_list va;
  119.  
  120.     va_start(va, id);
  121.     DisplayMessage(TRUE, id, va);
  122.     va_end(va);
  123. }
  124.  
  125.  
  126. VOID Warning (UINT id, ...)
  127. {
  128.     va_list va;
  129.  
  130.     va_start(va, id);
  131.     DisplayMessage(FALSE, id, va);
  132.     va_end(va);
  133. }
  134.  
  135.  
  136. VOID WriteOutput (PCSTR pcsz, int len)
  137. {
  138.     if (!g_fConvertNewlines)
  139.     {
  140.         DWORD wrote;
  141.         WriteFile(g_hOutput, pcsz, len, &wrote, NULL);
  142.         return;
  143.     }
  144.  
  145.     for (;;)
  146.     {
  147.         int towrite;
  148.     
  149.         PCSTR nl = strchr(pcsz, '\n');
  150.         if (nl)
  151.             towrite = nl - pcsz;
  152.         else
  153.             towrite = len;
  154.  
  155.         DWORD wrote;
  156.         WriteFile(g_hOutput, pcsz, towrite, &wrote, NULL);
  157.  
  158.         pcsz += towrite;
  159.         len -= towrite;
  160.  
  161.         if (nl)
  162.         {
  163.             WriteFile(g_hOutput, "\r\n", 2, &wrote, NULL);
  164.             pcsz++;
  165.             len--;
  166.         }
  167.  
  168.         if (!len)
  169.             break;
  170.     }
  171. }
  172.  
  173.  
  174. VOID WriteOutput (PCSTR pcsz)
  175. {
  176.     int len = strlen(pcsz);
  177.     WriteOutput(pcsz, len);
  178. }
  179.  
  180.  
  181. VOID WriteOutputW (PCWSTR pcwsz)
  182. {
  183.     CHAR buf[4096];
  184.     int len = WideCharToMultiByte(CP_ACP, 0, pcwsz, -1, buf, sizeof(buf)-1, NULL, NULL);
  185.     if (len > 0)
  186.     {
  187.         if (buf[len-1] == '\0')
  188.             len--;
  189.         else
  190.             buf[len] = '\0';
  191.  
  192.         if (g_fOutputIsConsole)
  193.             CharToOem(buf, buf);
  194.  
  195.         WriteOutput(buf, len);
  196.     }
  197. }
  198.  
  199.  
  200. VOID WriteOutputUtf8 (PCSTR pcszUtf8)
  201. {
  202.     PSTR pszAnsi;
  203.     if (Utf8ToAnsi(pcszUtf8, &pszAnsi))
  204.     {
  205.         if (!pszAnsi)
  206.         {
  207.             WriteOutput(pcszUtf8);
  208.         }
  209.         else
  210.         {
  211.             WriteOutput(pszAnsi);
  212.             delete pszAnsi;
  213.         }
  214.     }
  215. }
  216.  
  217.  
  218. VOID WriteOutputLongFmt (PCSTR fmt, ...)
  219. {
  220.     CHAR buf[4096];
  221.     va_list va;
  222.     int len;
  223.  
  224.     va_start(va, fmt);
  225.     len = g_pJVIEW->vsnprintf(buf, sizeof(buf), fmt, va);
  226.     va_end(va);
  227.  
  228.     if (len > 0)
  229.         WriteOutput(buf, len);
  230. }
  231.  
  232.  
  233. VOID WriteOutputFmt (PCSTR fmt, ...)
  234. {
  235.     CHAR buf[WRITE_MAX_SIZE_NORM_FMT];
  236.     va_list va;
  237.     int len;
  238.  
  239.     va_start(va, fmt);
  240.     len = vsprintf(buf, fmt, va);
  241.     va_end(va);
  242.  
  243.     WriteOutput(buf, len);
  244. }
  245.  
  246.  
  247. #define MAX_OUTPUT_WIDTH 4096
  248.  
  249. VOID WriteOutputEx (DWORD flags, PCSTR fmt, ...)
  250. {
  251.     // Allow space for ' 's we may insert into the format, plus the format itself.
  252.     CHAR fmtbuf[MAX_OUTPUT_WIDTH+80];
  253.     va_list va;
  254.  
  255.     PSTR pszAnsi = NULL;
  256.  
  257.     if (flags & WRITE_UTF8)
  258.     {
  259.         va_start(va, fmt);
  260.         
  261.         if (flags & (WRITE_LEFT_JUSTIFIED | WRITE_CENTERED | WRITE_RIGHT_JUSTIFIED | WRITE_WRAP | WRITE_FIT))
  262.         {
  263.             ULONG width = va_arg(va, ULONG);
  264.  
  265.             if (flags & WRITE_FIT)
  266.             {
  267.                 double pct = va_arg(va, double);
  268.                 if (pct != 1.0 && (flags & WRITE_WRAP))
  269.                 {
  270.                     va_arg(va, double);
  271.                     va_arg(va, ULONG);
  272.                 }
  273.             }
  274.         }
  275.  
  276.         va_list vasave = va;
  277.         PSTR pszUtf8 = va_arg(va, PSTR);
  278.  
  279.         if (!Utf8ToAnsi(pszUtf8, &pszAnsi))
  280.             return;
  281.  
  282.         if (pszAnsi)
  283.         {
  284.             va = vasave;
  285.             va_arg(va, PSTR) = pszAnsi;
  286.         }
  287.  
  288.         va_end(va);
  289.     }
  290.  
  291.     va_start(va, fmt);
  292.  
  293.     if (flags & (WRITE_LEFT_JUSTIFIED | WRITE_CENTERED | WRITE_RIGHT_JUSTIFIED | WRITE_WRAP | WRITE_FIT))
  294.     {
  295.         ULONG width = va_arg(va, ULONG);
  296.  
  297.         double pct = 0;
  298.         double pctused = 0;
  299.         ULONG spcused = 0;
  300.         if (flags & WRITE_FIT)
  301.         {
  302.             pct = va_arg(va, double);
  303.             if (pct != 1.0 && (flags & WRITE_WRAP))
  304.             {
  305.                 pctused = va_arg(va, double);
  306.                 spcused = va_arg(va, ULONG);
  307.             }
  308.         }
  309.  
  310.         if (g_OutputWidth)
  311.         {
  312.             if (fmt[0] == 's')
  313.             {
  314.                 ULONG indent = width;
  315.  
  316.                 if (flags & WRITE_FIT)
  317.                 {
  318.                     ULONG avail = g_OutputWidth - 1 - width;
  319.                     indent = spcused + (ULONG)(pctused*avail);
  320.                     width = (ULONG)(pct*avail);
  321.                     indent += width;
  322.                 }
  323.             
  324.                 va_list vasave = va;
  325.                 PSTR psz = va_arg(va, PSTR);
  326.                 va = vasave;
  327.  
  328.                 int len = strlen(psz);
  329.  
  330.                 if ((flags & WRITE_WRAP) && len > width)
  331.                 {
  332.                     sprintf(fmtbuf, "%%s\n%*s%s", indent, "", fmt+1);
  333.                 }
  334.                 else if (flags & WRITE_CENTERED)
  335.                 {
  336.                     ULONG spc;
  337.                     if (width >= len)
  338.                         spc = width - len;
  339.                     else
  340.                         spc = 0;
  341.  
  342.                     ULONG before = spc/2;
  343.                     ULONG after = spc-before;
  344.  
  345.                     sprintf(fmtbuf, "%*s%%%s%*s", before, "", fmt, after, "");
  346.                 }
  347.                 else
  348.                 {
  349.                     sprintf(fmtbuf, (flags & WRITE_RIGHT_JUSTIFIED) ? "%%%u%s" : "%%-%u%s", width, fmt);
  350.                 }
  351.  
  352.                 fmt = fmtbuf;
  353.             }
  354.             else
  355.             {
  356.                 sprintf(fmtbuf, (flags & WRITE_RIGHT_JUSTIFIED) ? "%%%u%s" : "%%-%u%s", width, fmt);
  357.  
  358.                 fmt = fmtbuf;
  359.             }
  360.         }
  361.         else
  362.         {
  363.             sprintf(fmtbuf, "%%%s", fmt);
  364.  
  365.             fmt = fmtbuf;
  366.         }
  367.     }
  368.  
  369.     CHAR buf[4096];
  370.     int len;
  371.  
  372.     if (flags & (WRITE_FIT | WRITE_BIG))
  373.         len = g_pJVIEW->vsnprintf(buf, sizeof(buf), fmt, va);
  374.     else    
  375.         len = vsprintf(buf, fmt, va);
  376.  
  377.     va_end(va);
  378.  
  379.     WriteOutput(buf, len);
  380.  
  381.     if (pszAnsi)
  382.         delete pszAnsi;
  383. }
  384.  
  385.  
  386. VOID WriteTime (PCSTR prefix, PCSTR suffix)
  387. {
  388.     SYSTEMTIME time;
  389.     GetLocalTime(&time);
  390.     WriteOutputFmt("%s%02u/%02u/%04u %02u:%02u:%02u%s",
  391.             prefix,
  392.             time.wMonth, time.wDay, time.wYear,
  393.             time.wHour, time.wMinute, time.wSecond,
  394.             suffix);
  395. }
  396.  
  397.  
  398. //------------------------------------------------------------------------
  399.  
  400.  
  401. STDMETHODIMP EventMonitor::JVIEWInitialize (IJVIEWProfilerUtils *putils, DWORD *pflags)
  402. {
  403.     if (!InitTimer())
  404.         return E_FAIL;
  405.  
  406.     (g_pJVIEW = putils)->AddRef();
  407.     *pflags = JVIEWPRF_INIT_SUPPORTS_PARAMS;
  408.     return S_OK;
  409. }
  410.  
  411.  
  412. struct ParamInfo
  413. {
  414.     PCSTR buf;
  415.     PCSTR opts;
  416.     BOOL failed;
  417. };
  418.  
  419. BOOL EnableCallOption (DWORD mask, ParamInfo *pinfo)
  420. {
  421.     if (pinfo->opts)
  422.     {
  423.         if ((g_ProfOptions & mask) != mask && (g_nMethodsToHook || g_nClassesToHook))
  424.         {
  425.             FatalError(IDS_MULTOPTSWITHCALLSPECS);
  426.             return FALSE;
  427.         }
  428.  
  429.         PCSTR p = pinfo->opts;
  430.  
  431.         if (*p != '\0')
  432.         {
  433.             for (;;)
  434.             {
  435.                 PCSTR pstart = p;
  436.                 PCSTR pmethsep = NULL;
  437.  
  438.                 BOOL fClass = TRUE;
  439.                 BOOL fParsing = FALSE;
  440.                 BOOL fWildcard = FALSE;
  441.  
  442.                 CHAR ch;
  443.  
  444.                 for (;;)
  445.                 {
  446.                     ch = *p;
  447.                     
  448.                     if (ch == ',' || ch == '+')
  449.                         break;
  450.  
  451.                     if (ch <= 32)
  452.                     {
  453.                         if (ch == '\0')
  454.                             break;
  455.                     
  456.                         if (fParsing)
  457.                         {
  458.                             FatalError(IDS_INVALIDMETHODSIG, p);
  459.                             return FALSE;
  460.                         }
  461.  
  462.                         pstart = p+1;
  463.                     }
  464.                     else
  465.                     {
  466.                         if (fParsing)
  467.                         {
  468.                             if (fWildcard)
  469.                             {
  470.                                 FatalError(IDS_NONTRAILINGWILDCARD, p-1);
  471.                                 return FALSE;
  472.                             }
  473.  
  474.                             if (ch == '.')
  475.                             {
  476.                                 if (fClass)
  477.                                 {
  478.                                     pmethsep = p;
  479.                                 }
  480.                             }
  481.                             else if (ch == '(')
  482.                             {
  483.                                 fClass = FALSE;
  484.                             }
  485.                             else if (ch == '*')
  486.                             {
  487.                                 fWildcard = TRUE;
  488.                             }
  489.                         }
  490.                         else
  491.                         {
  492.                             if (ch == '.' || ch == '(' || ch == ';' || ch == '/' || ch == ')')
  493.                             {
  494.                                 FatalError(IDS_INVALIDMETHODSIG, p);
  495.                                 return FALSE;
  496.                             }
  497.  
  498.                             if (ch == '*')
  499.                             {
  500.                                 fWildcard = TRUE;
  501.                             }
  502.                             
  503.                             fParsing = TRUE;
  504.                         }
  505.                     }
  506.  
  507.                     p++;
  508.                 }
  509.  
  510.                 PCSTR pend = p;
  511.  
  512.                 if (pstart < pend)
  513.                 {
  514.                     for (;;)
  515.                     {
  516.                         PSTR **ppArray;
  517.                         ULONG *pCount;
  518.  
  519.                         if (fClass)
  520.                         {
  521.                             ppArray = &g_rgpszClassesToHook;
  522.                             pCount = &g_nClassesToHook;
  523.                         }
  524.                         else
  525.                         {
  526.                             ppArray = &g_rgpszMethodsToHook;
  527.                             pCount = &g_nMethodsToHook;
  528.                         }
  529.  
  530.                         if (GrowStringArray(ppArray, pCount))
  531.                         {
  532.                             int len = pend - pstart;
  533.                             PSTR psz = new CHAR[len+1];
  534.                             CopyMemory(psz, pstart, len);
  535.                             psz[len] = '\0';
  536.  
  537.                             (*ppArray)[*pCount - 1] = psz;
  538.  
  539.                             if (fClass)
  540.                                 pmethsep = pend;
  541.  
  542.                             if (pmethsep)
  543.                             {
  544.                                 pmethsep = psz + (pmethsep - pstart);
  545.                                 
  546.                                 while (psz < pmethsep)
  547.                                 {
  548.                                     if (*psz == '/')
  549.                                         *psz = '.';
  550.                                     psz++;
  551.                                 }
  552.                             }
  553.                         }
  554.                         
  555.                         if (!fWildcard || !fClass)
  556.                             break;
  557.  
  558.                         fClass = FALSE;
  559.                         pmethsep = NULL;
  560.                     }
  561.                 }
  562.  
  563.                 if (ch == '\0')
  564.                     break;
  565.  
  566.                 p++;
  567.  
  568.                 if (ch == ',')
  569.                     break;
  570.             }
  571.         }
  572.  
  573.         pinfo->buf = p;
  574.     }
  575.  
  576.     g_ProfOptions |= (OPT_PROF_CALLS | mask);
  577.     return TRUE;
  578. }
  579.  
  580.  
  581. BOOL MatchParam (ParamInfo *pinfo, PCSTR param, int paramlen, BOOL fHasOptions)
  582. {
  583.     if (pinfo->failed)
  584.         return FALSE;
  585.  
  586.     PCSTR buf = pinfo->buf;
  587.  
  588.     if (strnicmp(buf, param, paramlen) == 0)
  589.     {
  590.         PCSTR p = &buf[paramlen];
  591.  
  592.         for (;;)
  593.         {
  594.             CHAR endch = *p;
  595.  
  596.             if (endch == '\0')
  597.             {
  598.                 pinfo->buf = p;
  599.                 pinfo->opts = NULL;
  600.                 return TRUE;
  601.             }
  602.  
  603.             p++;
  604.  
  605.             if (endch == ',')
  606.             {
  607.                 pinfo->buf = p;
  608.                 pinfo->opts = NULL;
  609.                 return TRUE;
  610.             }
  611.  
  612.             if (endch <= 32)
  613.                 continue;
  614.  
  615.             if (endch == '=')
  616.             {
  617.                 if (!fHasOptions)
  618.                 {
  619.                     FatalError(IDS_NOSETTINGSFOROPT, param);
  620.                     pinfo->failed = TRUE;
  621.                     break;
  622.                 }
  623.                     
  624.                 pinfo->opts = p;
  625.                 return TRUE;
  626.             }
  627.         }
  628.     }
  629.  
  630.     return FALSE;
  631. }
  632.  
  633. #define MatchParam(pinfo,s,fHasOptions) MatchParam(pinfo, s, sizeof(s)-1, fHasOptions)
  634.  
  635.  
  636. STDMETHODIMP EventMonitor::ParseParameters (PCSTR pcszParams)
  637. {
  638.     const CHAR *p = pcszParams;
  639.  
  640.     ParamInfo info;
  641.     info.failed = FALSE;
  642.  
  643.     for (;;)
  644.     {
  645.         CHAR ch = *p++;
  646.  
  647.         if (ch == '\0')
  648.             break;
  649.  
  650.         if (ch <= 32)
  651.             continue;
  652.  
  653.         info.buf = p-1;
  654.  
  655.         if      (MatchParam(&info, "calls", TRUE)
  656.               || MatchParam(&info, "calltimes", TRUE))
  657.         {
  658.             if (!EnableCallOption(OPT_CALL_TIMES, &info))
  659.                 goto failed;
  660.         }
  661.         else if (MatchParam(&info, "calltrace", TRUE))
  662.         {
  663.             if (!EnableCallOption(OPT_CALL_TRACE, &info))
  664.                 goto failed;
  665.         }
  666.         else if (MatchParam(&info, "callparams", TRUE))
  667.         {
  668.             if (!EnableCallOption(OPT_CALL_TRACE | OPT_CALL_TRACE_PARAMS, &info))
  669.                 goto failed;
  670.         }
  671.         else if (MatchParam(&info, "permethodalloc", FALSE))
  672.         {
  673.             g_ProfOptions |= (OPT_PROF_ALLOC | OPT_ALLOC_PER_METHOD);
  674.         }
  675.         else if (MatchParam(&info, "perclassalloc", FALSE))
  676.         {
  677.             g_ProfOptions |= (OPT_PROF_ALLOC | OPT_ALLOC_PER_CLASS);
  678.         }
  679.         else if (MatchParam(&info, "gc", FALSE))
  680.         {
  681.             g_ProfOptions |= (OPT_PROF_GC | OPT_GC_SUMMARY);
  682.         }
  683.         else if (MatchParam(&info, "heapdump", FALSE))
  684.         {
  685.             g_ProfOptions |= (OPT_PROF_GC | OPT_DUMP_HEAP);
  686.         }
  687.         else if (MatchParam(&info, "verbose", FALSE))
  688.         {
  689.             g_ProfOptions |= OPT_VERBOSE;
  690.         }
  691.         else if (MatchParam(&info, "file", TRUE))
  692.         {
  693.             if (!info.opts)
  694.             {
  695.                 FatalError(IDS_MISSINGFILENAME);
  696.                 goto failed;
  697.             }
  698.  
  699.             PCSTR comma = strchr(info.opts, ',');
  700.             PCSTR sep = comma;
  701.             if (!sep)
  702.                 sep = info.opts+strlen(info.opts);
  703.  
  704.             int len = sep - info.opts;
  705.  
  706.             g_pszOutputFileName = new CHAR[len+1];
  707.             if (!g_pszOutputFileName)
  708.                 goto failed;
  709.  
  710.             CopyMemory(g_pszOutputFileName, info.opts, len);
  711.             g_pszOutputFileName[len] = '\0';
  712.  
  713.             if (comma)
  714.                 sep++;
  715.             else
  716.                 break;
  717.             info.buf = sep;
  718.         }
  719.         else if (MatchParam(&info, "sample", TRUE))
  720.         {
  721.             g_ProfOptions |= OPT_SAMPLE;
  722.  
  723.             if (info.opts)
  724.             {
  725.                 if (g_fSamplingFrequencySpecified)
  726.                 {
  727.                     FatalError(IDS_MULTSAMPFREQ, info.opts);
  728.                         goto failed;
  729.                 }
  730.  
  731.                 g_SamplingFrequency = atoi(info.opts);
  732.                 if (g_SamplingFrequency == 0)
  733.                 {
  734.                     FatalError(IDS_INVALIDSAMPFREQ, info.opts);
  735.                         goto failed;
  736.                 }
  737.  
  738.                 g_fSamplingFrequencySpecified = TRUE;
  739.  
  740.                 PCSTR comma = strchr(info.opts, ',');
  741.                 if (comma)
  742.                     info.buf = comma+1;
  743.                 else
  744.                     break;
  745.             }
  746.         }
  747.         else if (MatchParam(&info, "table", FALSE))
  748.         {
  749.             g_ProfOptions |= OPT_TABLE;
  750.         }
  751.         else
  752.         {
  753.             if (info.failed)
  754.                 goto failed;
  755.  
  756.             FatalError(IDS_INVALIDOPTION, info.buf);
  757.             goto failed;
  758.         }
  759.  
  760.         p = info.buf;
  761.     }
  762.  
  763.     if ((g_ProfOptions & (OPT_PROF_CALLS | OPT_SAMPLE)) == (OPT_PROF_CALLS | OPT_SAMPLE))
  764.     {
  765.         FatalError(IDS_DONTSAMPLEANDHOOK);
  766.  
  767. failed:
  768.         return E_FAIL;
  769.     }
  770.  
  771.     return S_OK;
  772. }
  773.  
  774.  
  775. STDMETHODIMP_(PSTR) EventMonitor::GetUsageString ()
  776. {
  777.     int size = 4096;
  778.     PSTR pszUsage = (PSTR)CoTaskMemAlloc(size);
  779.  
  780.     if (pszUsage)
  781.     {
  782.         CHAR *p = pszUsage;
  783.  
  784.         for (unsigned i = IDS_USAGE; ; i++)
  785.         {
  786.             int len = g_pJVIEW->LoadResourceString(g_hInst, i, p, size);
  787.             if (!len)
  788.             {
  789.                 CoTaskMemFree(pszUsage);
  790.                 return NULL;
  791.             }
  792.  
  793.             if (p[0] == '~')
  794.             {
  795.                 p[0] = '\0';
  796.                 break;
  797.             }
  798.  
  799.             p += len;
  800.         }
  801.     }
  802.  
  803.     return pszUsage;
  804. }
  805.  
  806.  
  807. //------------------------------------------------------------------------
  808.  
  809.  
  810. VOID EventMonitor::OnVMInitialization ()
  811. {
  812.     m_fVMInitialized = TRUE;
  813.  
  814.     HMODULE hmodMSJava = GetModuleHandle("MSJAVA.DLL");
  815.     if (hmodMSJava)
  816.     {
  817.         typedef BOOL __cdecl AddModuleResourceClassSourceProc (HMODULE hMod, DWORD dwResID);
  818.         AddModuleResourceClassSourceProc *pfnAddModuleResourceClassSource;
  819.  
  820.         pfnAddModuleResourceClassSource = (AddModuleResourceClassSourceProc*)GetProcAddress(hmodMSJava, "AddModuleResourceClassSource");
  821.         if (pfnAddModuleResourceClassSource)
  822.         {
  823.             (*pfnAddModuleResourceClassSource)(g_hInst, JEX_DEFAULT_CLASS_RESOURCE_ID);
  824.         }
  825.     }
  826.  
  827.     m_sampler.OnVMInitialization();
  828. }
  829.  
  830.  
  831. //------------------------------------------------------------------------
  832.  
  833.  
  834. ThreadRecord *EventMonitor::CreateCurrentThreadRecord ()
  835. {
  836.     ThreadID vmid = NULL;
  837.     DWORD tid = GetCurrentThreadId();
  838.  
  839.     if (m_monitor_info2)
  840.         m_monitor_info2->GetCurrentThread(&vmid);
  841.  
  842.     ThreadRecord *pThread = GetThreadRecord(vmid, tid);
  843.     if (pThread)
  844.         TlsSetValue(m_threadtls, pThread);
  845.  
  846.     return pThread;
  847. }
  848.  
  849.  
  850. ThreadRecord *EventMonitor::GetThreadRecord (ThreadID vmid, DWORD tid)
  851. {
  852.     ThreadRecord *ret = NULL;
  853.  
  854.     EnterCriticalSection(&m_ThreadEventCS);
  855.     {
  856.         for (ULONG i = 0; i < m_nthreads; i++)
  857.         {
  858.             ThreadRecord *prec = m_rgpthreads[i];
  859.             if (prec->tid == tid)
  860.             {
  861.                 prec->vmid = vmid;
  862.                 ret = prec;
  863.                 break;
  864.             }
  865.         }
  866.  
  867.         ret = CreateThreadRecord(vmid, tid);
  868.     }
  869.     LeaveCriticalSection(&m_ThreadEventCS);
  870.  
  871.     return ret;
  872. }
  873.  
  874.  
  875. ThreadRecord *EventMonitor::CreateThreadRecord (ThreadID vmid, DWORD tid)
  876. {
  877.     ThreadRecord *pThread = NULL;
  878.  
  879.     if (m_nthreads >= m_maxthreads)
  880.     {
  881.         GrowPtrArray((PVOID**)&m_rgpthreads, &m_maxthreads, (m_maxthreads+1)*2);
  882.     }
  883.  
  884.     if (m_nthreads < m_maxthreads)
  885.     {
  886.         pThread = new ThreadRecord();
  887.         if (pThread)
  888.         {
  889.             ZeroMemory(pThread, sizeof(*pThread));
  890.         
  891.             pThread->vmid = vmid;
  892.             pThread->tid = tid;
  893.  
  894.             m_rgpthreads[m_nthreads++] = pThread;
  895.         }
  896.     }
  897.  
  898.     return pThread;
  899. }
  900.  
  901.  
  902. //------------------------------------------------------------------------
  903.  
  904.  
  905. EventMonitor::EventMonitor ()
  906. {
  907.     m_refcount = 1;
  908.  
  909.     m_monitor_info = NULL;
  910.     m_monitor_info2 = NULL;
  911.     m_monitor_info3 = NULL;
  912.     m_monitor_info4 = NULL;
  913.  
  914.     m_VMRelease = VM_CURRENT;
  915.  
  916.     m_fVMInitialized = FALSE;
  917.     m_fVMTerminated = FALSE;
  918.  
  919.     m_threadtls = TLS_OUT_OF_INDEXES;
  920.     m_rgpthreads = NULL;
  921.     m_nthreads = 0;
  922.     m_maxthreads = 0;
  923.     InitializeCriticalSection(&m_ThreadEventCS);
  924. }
  925.  
  926.  
  927. EventMonitor::~EventMonitor(void)
  928. {
  929.     g_EventMonitor = NULL;
  930.  
  931.     m_callprof.Destruct();
  932.     m_sampler.Destruct();
  933.     m_calltracer.Destruct();
  934.     m_allocprof.Destruct();
  935.     m_gcprof.Destruct();
  936.  
  937.     if (m_monitor_info4)
  938.         m_monitor_info4->Release();
  939.  
  940.     if (m_monitor_info3)
  941.         m_monitor_info3->Release();
  942.  
  943.     if (m_monitor_info2)
  944.         m_monitor_info2->Release();
  945.  
  946.     if (m_monitor_info)
  947.         m_monitor_info->Release();
  948.  
  949.     if (m_rgpthreads)
  950.         delete(m_rgpthreads);
  951.     DeleteCriticalSection(&m_ThreadEventCS);
  952.     if (m_threadtls != TLS_OUT_OF_INDEXES)
  953.         TlsFree(m_threadtls);
  954. }
  955.  
  956.  
  957. VOID EventMonitor::ShutdownWorker (BOOL fNormal)
  958. {
  959.     if (!g_EventMonitor)
  960.         return;
  961.  
  962.     g_EventMonitor = NULL;
  963.     
  964.     if (!fNormal)
  965.         WriteOutput("Process terminated.\n");
  966.  
  967.     WriteTime("End time: ", "\n");
  968.  
  969.     m_fVMTerminated = TRUE;
  970.  
  971.     m_callprof.SpewResults();
  972.     m_allocprof.SpewResults();
  973.     m_sampler.SpewSamplerResults();
  974.  
  975.     WriteOutput("--- End of profiler output ---\n");
  976.  
  977.     CloseHandle(g_hOutput);
  978.     g_hOutput = INVALID_HANDLE_VALUE;
  979. }
  980.  
  981.  
  982. //------------------------------------------------------------------------
  983.  
  984.  
  985. ULONG EventMonitor::AddRef ()
  986. {
  987.     return (ULONG)InterlockedIncrement((LPLONG)&m_refcount);
  988. }
  989.  
  990.  
  991. ULONG EventMonitor::Release ()
  992. {
  993.     ULONG refcount = (ULONG)InterlockedDecrement((LPLONG)&m_refcount);
  994.     if (!refcount)
  995.         delete this;
  996.     return refcount;
  997. }
  998.  
  999.  
  1000. STDMETHODIMP EventMonitor::QueryInterface (REFIID riid, void ** ppv)
  1001. {
  1002.     if (   riid == IID_IJavaEventMonitor
  1003.         || riid == IID_IJavaEventMonitor2
  1004.         || riid == IID_IUnknown)
  1005.     {
  1006.         *ppv = (IJavaEventMonitor2*)this;
  1007.     }
  1008.     else if (riid == IID_IObjectAllocationCallback)
  1009.     {
  1010.         *ppv = (IObjectAllocationCallback*)this;
  1011.     }
  1012.     else if (riid == IID_IJVIEWProfiler)
  1013.     {
  1014.         *ppv = (IJVIEWProfiler*)this;
  1015.     }
  1016.     else
  1017.     {
  1018.         *ppv = NULL;
  1019.         return E_NOINTERFACE;
  1020.     }
  1021.  
  1022.     AddRef();
  1023.     return S_OK;
  1024. }
  1025.  
  1026.  
  1027. //------------------------------------------------------------------------
  1028.  
  1029.  
  1030. STDMETHODIMP EventMonitor::Initialize(LPCSTR pclass_file_name, IJavaEventMonitorIDInfo *pmonitor_info, DWORD java_flags, DWORD *prequested_events)
  1031. {
  1032.     g_fErrorMessageDisplayed = FALSE;
  1033.  
  1034.     HRESULT hr = S_OK;
  1035.  
  1036.     (m_monitor_info = pmonitor_info)->AddRef();
  1037.  
  1038.     if (m_monitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo4, (void **)&m_monitor_info4) != S_OK)
  1039.     {
  1040.         m_monitor_info4 = NULL;
  1041.         m_VMRelease = VM_SDK31;
  1042.     }
  1043.  
  1044.     if (m_monitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo3, (void **)&m_monitor_info3) != S_OK)
  1045.     {
  1046.         m_monitor_info3 = NULL;
  1047.         m_VMRelease = VM_SDK30PR1;
  1048.     }
  1049.  
  1050.     if (m_monitor_info->QueryInterface(IID_IJavaEventMonitorIDInfo2, (void **)&m_monitor_info2) != S_OK)
  1051.     {
  1052.         m_monitor_info2 = NULL;
  1053.         m_VMRelease = VM_IE40;
  1054.     }
  1055.  
  1056.     // These are the characteristics of the IE 4 VM, the first VM that
  1057.     // supported profiling.  It did not support GetProfilingCapabilities.
  1058.  
  1059.     DWORD SupportedStates = (  JVM_STATE_INTERPRETER_ENABLED
  1060. #ifdef _X86_
  1061.                              | JVM_STATE_FAST_INTERPRETER_ENABLED
  1062.                              | JVM_STATE_JIT_COMPILER_ENABLED
  1063. #endif
  1064.                              | JVM_STATE_DEBUGGER_ENABLED);
  1065.  
  1066.     // Note that JVM_MONITOR_SOURCE_LINE_EXECUTION,
  1067.     // JVM_MONITOR_MONITOR_OPERATIONS, and JVM_MONITOR_THREADS were defined in
  1068.     // the original IE4 jevmon.idl, but they were not fully supported by that
  1069.     // VM.
  1070.  
  1071.     DWORD SupportedEventCategories = (  JVM_MONITOR_CLASS_LOADS
  1072.                                       | JVM_MONITOR_METHOD_CALLS
  1073.                                       | JVM_MONITOR_JIT_COMPILATION
  1074.                                       | JVM_MONITOR_BYTE_CODE_EXECUTION
  1075.                                       | JVM_MONITOR_EXCEPTIONS
  1076.                                       | JVM_MONITOR_GARBAGE_COLLECTIONS);
  1077.  
  1078.     JAVA_EXECUTION_MODEL LastSupportedExecModel = JVM_EXECUTION_COM;
  1079.  
  1080.     JVM_EVENT_TYPE LastSupportedEventType = JVM_EVENT_TYPE_SHUTDOWN;
  1081.  
  1082.     // IJavaEventMonitor2 was not supported by the IE4 VM.
  1083.     JVM_EVENT_TYPE2 LastSupportedEventType2 = (JVM_EVENT_TYPE2)-1;
  1084.  
  1085.     if (m_monitor_info2 != NULL)
  1086.     {
  1087.         LPSTR pszClassPath;
  1088.         hr = m_monitor_info2->GetClassPath(&pszClassPath);
  1089.         if (hr == S_OK)
  1090.         {
  1091.             WriteOutputLongFmt("class path: %s\n", pszClassPath);
  1092.  
  1093.             CoTaskMemFree(pszClassPath);
  1094.         }
  1095.  
  1096.         hr = m_monitor_info2->GetProfilingCapabilities(
  1097.             &SupportedStates,
  1098.             &SupportedEventCategories,
  1099.             &LastSupportedExecModel,
  1100.             &LastSupportedEventType,
  1101.             &LastSupportedEventType2);
  1102.     }
  1103.  
  1104.  
  1105.     if (!(g_ProfOptions & ~OPT_NON_EVENT_OPTIONS))
  1106.     {
  1107.         g_ProfOptions |= OPT_DEFAULT_OPTIONS;
  1108.     }
  1109.  
  1110.  
  1111.     if (hr == S_OK)
  1112.     {
  1113.         if (g_pszOutputFileName)
  1114.         {
  1115.             g_hOutput = CreateFile(
  1116.                     g_pszOutputFileName,
  1117.                     GENERIC_WRITE,
  1118.                     FILE_SHARE_READ,
  1119.                     NULL,
  1120.                     OPEN_ALWAYS,
  1121.                     0,
  1122.                     NULL);
  1123.             if (g_hOutput == INVALID_HANDLE_VALUE)
  1124.             {
  1125.                 FatalError(IDS_CANTAPPEND, g_pszOutputFileName);
  1126.                 hr = HRESULT_FROM_WIN32(GetLastError());
  1127.             }
  1128.             else
  1129.             {
  1130.                 LONG dwSizeHi = 0;
  1131.                 LONG dwSizeLo = SetFilePointer(g_hOutput, 0, &dwSizeHi, FILE_END);
  1132.             }
  1133.  
  1134.             g_OutputWidth = 120;
  1135.         }
  1136.         else
  1137.         {
  1138.             g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  1139.  
  1140.             if (g_ProfOptions & OPT_TABLE)
  1141.             {
  1142.                 g_OutputWidth = 0;
  1143.             }
  1144.             else
  1145.             {
  1146.                 CONSOLE_SCREEN_BUFFER_INFO coninfo;
  1147.                 if (GetConsoleScreenBufferInfo(g_hOutput, &coninfo))
  1148.                 {
  1149.                     g_OutputWidth = coninfo.dwSize.X;
  1150.                     if (g_OutputWidth > MAX_OUTPUT_WIDTH)
  1151.                         g_OutputWidth = MAX_OUTPUT_WIDTH;
  1152.                     g_fOutputIsConsole = TRUE;
  1153.                 }
  1154.                 else
  1155.                 {
  1156.                     g_OutputWidth = 80;
  1157.                 }
  1158.             }
  1159.         }
  1160.     }
  1161.  
  1162.  
  1163.     if (hr == S_OK)
  1164.     {
  1165.         BOOL first = TRUE;
  1166.  
  1167.         WriteOutput("VM state:");
  1168.  
  1169. #define SPEWSTATE(flag,descr) \
  1170.         if ((java_flags & (flag)) != 0) \
  1171.         { \
  1172.             if (!first) \
  1173.                 WriteOutput(","); \
  1174.             else \
  1175.                 first = FALSE; \
  1176.             WriteOutput(" " descr); \
  1177.         }
  1178.  
  1179.         SPEWSTATE(JVM_STATE_INTERPRETER_ENABLED, "Interpreter loop");
  1180.         SPEWSTATE(JVM_STATE_FAST_INTERPRETER_ENABLED, "Fast interpreter loop");
  1181.         SPEWSTATE(JVM_STATE_JIT_COMPILER_ENABLED, "JIT compiler");
  1182.         SPEWSTATE(JVM_STATE_DEBUGGER_ENABLED, "Debugging");
  1183.  
  1184. #undef SPEWSTATE
  1185.  
  1186.         WriteOutput("\n");
  1187.     }
  1188.  
  1189.  
  1190.     if (hr == S_OK)
  1191.     {
  1192.         hr = m_gcprof.Initialize(this);
  1193.     }
  1194.  
  1195.     if (hr == S_OK)
  1196.     {
  1197.         hr = m_callprof.Initialize(this);
  1198.     }
  1199.  
  1200.     if (hr == S_OK)
  1201.     {
  1202.         hr = m_calltracer.Initialize(this);
  1203.     }
  1204.  
  1205.     if (hr == S_OK)
  1206.     {
  1207.         hr = m_allocprof.Initialize(this);
  1208.     }
  1209.  
  1210.     if (hr == S_OK)
  1211.     {
  1212.         hr = m_sampler.Initialize(this, &m_callprof);
  1213.     }
  1214.  
  1215.  
  1216.     // Install an allocation hook if any form of allocation profiling is enabled.
  1217.  
  1218.     if (hr == S_OK)
  1219.     {
  1220.         if (g_ProfOptions & OPT_PROF_ALLOC)
  1221.         {
  1222.             UINT idError = IDS_CANTHOOKALLOCS;
  1223.  
  1224.             IJavaHeapMonitor *pheapmon;
  1225.             hr = pmonitor_info->QueryInterface(IID_IJavaHeapMonitor, (PVOID*)&pheapmon);
  1226.             if (hr == S_OK)
  1227.             {
  1228.                 IObjectAllocationCallback *alloccb;
  1229.                 hr = QueryInterface(IID_IObjectAllocationCallback, (PVOID*)&alloccb);
  1230.                 if (hr == S_OK)
  1231.                 {
  1232.                     hr = pheapmon->NotifyOnObjectAllocations(alloccb);
  1233.  
  1234.                     alloccb->Release();
  1235.                 }
  1236.             }
  1237.             else
  1238.             {
  1239.                 idError = IDS_ALLOCHOOKNOTSUP;
  1240.             }
  1241.  
  1242.             if (hr != S_OK)
  1243.             {
  1244.                 FatalError(idError);
  1245.             }
  1246.         }
  1247.     }
  1248.  
  1249.  
  1250.     // Determine which events are needed based on the specified profiling options.
  1251.  
  1252.     if (hr == S_OK)
  1253.     {
  1254.         DWORD events = 0;
  1255.  
  1256.         if (g_ProfOptions & OPT_PROF_CALLS)
  1257.         {
  1258.             if (LastSupportedEventType2 < JVM_EVENT_TYPE2_EXCEPTION_THROWN)
  1259.             {
  1260.                 // TODO: The call profiling implementation here depends in
  1261.                 // IJavaEventMonitor2::MethodExit2 and
  1262.                 // JVM_EVENT_TYPE2_EXCEPTION_THROWN.  To implement this for the
  1263.                 // IE4 VM, the stack must be mirrored to know the method that
  1264.                 // each call is returning to.  MethodExit only provides the
  1265.                 // StackID.
  1266.  
  1267.                 FatalError(IDS_CALLPROFNOTIMPFORIE4VM);
  1268.                 hr = E_FAIL;
  1269.             }
  1270.  
  1271.             if (hr == S_OK)
  1272.             {
  1273.                 if (g_nClassesToHook + g_nMethodsToHook)
  1274.                 {
  1275.                     events |= (JVM_MONITOR_CLASS_LOADS | JVM_MONITOR_SPECIFIC_METHOD_CALLS);
  1276.  
  1277.                     if (!(SupportedEventCategories & JVM_MONITOR_SPECIFIC_METHOD_CALLS) || !m_monitor_info3)
  1278.                     {
  1279.                         FatalError(IDS_SPECMETHODSNOTSUP);
  1280.                         hr = E_FAIL;
  1281.                     }
  1282.                 }
  1283.                 else
  1284.                 {
  1285.                     events |= JVM_MONITOR_METHOD_CALLS;
  1286.                 }
  1287.  
  1288.                 events |= (JVM_MONITOR_THREADS | JVM_MONITOR_EXCEPTIONS);
  1289.             }
  1290.         }
  1291.  
  1292.         if (hr == S_OK)
  1293.         {
  1294.             if (g_ProfOptions & OPT_PROF_ALLOC)
  1295.             {
  1296.                 events |= JVM_MONITOR_GARBAGE_COLLECTIONS;
  1297.  
  1298.                 if (g_ProfOptions & OPT_ALLOC_PER_METHOD)
  1299.                 {
  1300.                     if (LastSupportedEventType2 < JVM_EVENT_TYPE2_STACK_TRACE)
  1301.                     {
  1302.                         FatalError(IDS_STACKTRACENOTSUP);
  1303.                         hr = E_FAIL;
  1304.                     }
  1305.  
  1306.                     events |= JVM_MONITOR_THREADS;
  1307.                 }
  1308.             }
  1309.         }
  1310.  
  1311.         if (hr == S_OK)
  1312.         {
  1313.             if (g_ProfOptions & OPT_PROF_GC)
  1314.             {
  1315.                 events |= JVM_MONITOR_GARBAGE_COLLECTIONS;
  1316.             }
  1317.         }
  1318.  
  1319.         if (hr == S_OK)
  1320.         {
  1321.             if (g_ProfOptions & OPT_SAMPLE)
  1322.             {
  1323.                 if (!(SupportedEventCategories & JVM_MONITOR_SAMPLING))
  1324.                 {
  1325.                     FatalError(IDS_SAMPLINGNOTSUP);
  1326.                     hr = E_FAIL;
  1327.                 }
  1328.  
  1329.                 events |= (JVM_MONITOR_THREADS | JVM_MONITOR_SAMPLING);
  1330.  
  1331.                 if (LastSupportedEventType2 < JVM_EVENT_TYPE2_INITIALIZED)
  1332.                 {
  1333.                     // If this event is not supported, then presumably
  1334.                     // IJavaEventMonitorIDInfo2::SampleThreadLocation will
  1335.                     // simply fail until the VM is fully initialized.
  1336.  
  1337.                     OnVMInitialization();
  1338.                 }
  1339.  
  1340.                 // We won't bother to check for JVM_EVENT_TYPE_SHUTDOWN - if
  1341.                 // it's not supported, VM apis must already be safe to call
  1342.                 // during shutdown.  Also, the VM cannot reliably dispatch
  1343.                 // this event, so shutdown code must already assume that this
  1344.                 // event may never be received.
  1345.             }
  1346.         }
  1347.  
  1348.  
  1349.         if (g_ProfOptions & OPT_VERBOSE)
  1350.         {
  1351.             events |=   JVM_MONITOR_CLASS_LOADS
  1352.                       | JVM_MONITOR_EXCEPTIONS
  1353.                       | JVM_MONITOR_GARBAGE_COLLECTIONS
  1354.                       | JVM_MONITOR_THREADS;
  1355.  
  1356.             events &= SupportedEventCategories;
  1357.         }
  1358.  
  1359.  
  1360.         if (hr == S_OK && (SupportedEventCategories & events) != events)
  1361.         {
  1362.             FatalError(IDS_OPTNOTSUP);
  1363.             hr = E_FAIL;
  1364.         }
  1365.  
  1366.  
  1367.         if (hr == S_OK)
  1368.         {
  1369.             if (events & JVM_MONITOR_THREADS)
  1370.             {
  1371.                 m_threadtls = TlsAlloc();
  1372.                 if (m_threadtls == TLS_OUT_OF_INDEXES)
  1373.                     hr = E_OUTOFMEMORY;
  1374.             }
  1375.         }
  1376.  
  1377.         if (hr == S_OK)
  1378.         {
  1379.             *prequested_events = events;
  1380.  
  1381.             if (m_monitor_info4)
  1382.             {
  1383.                 // Enabling these two options allows the VM to substantially
  1384.                 // reduce method call event overhead.
  1385.  
  1386.                 DWORD initopts =   JVM_INIT_OPT_GC_SAFE_METHOD_CALLS
  1387.                                  | JVM_INIT_OPT_WONT_TOGGLE_METHOD_CALL_EVENTS;
  1388.  
  1389.                 // Enabling these two removes slightly more.
  1390.  
  1391.                 initopts |= JVM_INIT_OPT_FP_SAFE_METHOD_CALLS;
  1392.                                  
  1393.                 if (!(g_ProfOptions & OPT_CALL_TRACE_PARAMS))
  1394.                     initopts |= JVM_INIT_OPT_RETURN_VALUE_NOT_NEEDED;
  1395.  
  1396.                 m_monitor_info4->SetMonitorInitializationOptions(initopts);
  1397.             }
  1398.         }
  1399.     }
  1400.  
  1401.  
  1402.     if (g_ProfOptions & OPT_VERBOSE)
  1403.     {
  1404.         // TODO: spew event mask
  1405.     }
  1406.  
  1407.  
  1408.     if (hr == S_OK)
  1409.     {
  1410.         g_EventMonitor = this;
  1411.     
  1412.         WriteTime("Start time: ", "\n");
  1413.     }
  1414.     else
  1415.     {
  1416.         // Returning a non-S_OK value detaches the profiler.  If some path
  1417.         // through here didn't indicate a failure to the user, this is our
  1418.         // last chance to do so.
  1419.  
  1420.         if (!g_fErrorMessageDisplayed)
  1421.             FatalError(IDS_CANTPROFILE);
  1422.     }
  1423.  
  1424.  
  1425.     return(hr);
  1426. }
  1427.  
  1428.  
  1429. STDMETHODIMP EventMonitor::NotifyEvent(JVM_EVENT_TYPE event, UniqueID event_id)
  1430. {
  1431.     HRESULT hr;
  1432.  
  1433.     switch (event)
  1434.     {
  1435.         ThreadRecord *pThread;
  1436.     
  1437.         case JVM_EVENT_TYPE_THREAD_CREATE:          // A Java threadID is being created (ThreadID created)
  1438.  
  1439.             pThread = NULL;
  1440.  
  1441.             if (m_monitor_info2)
  1442.             {
  1443.                 DWORD tid = 0;
  1444.                 if (SUCCEEDED(m_monitor_info2->ThreadInformation((ThreadID)event_id, &tid)))
  1445.                     pThread = GetThreadRecord((ThreadID)event_id, tid);
  1446.             }
  1447.  
  1448.             if (g_ProfOptions & OPT_VERBOSE)
  1449.             {
  1450.                 if (pThread)
  1451.                     WriteOutputFmt("Thread %x created\n", pThread->tid);
  1452.                 else
  1453.                     WriteOutput("Thread created\n");
  1454.             }
  1455.  
  1456.             break;
  1457.  
  1458.         case JVM_EVENT_TYPE_THREAD_DESTROY:         // A Java threadID is being destroyed (ThreadID destroyed)
  1459.  
  1460.             pThread = NULL;
  1461.  
  1462.             EnterCriticalSection(&m_ThreadEventCS);
  1463.             {
  1464.                 ThreadID vmid = (ThreadID)event_id;
  1465.                 DWORD tid = 0;
  1466.  
  1467.                 if (m_monitor_info2)
  1468.                     m_monitor_info2->ThreadInformation(vmid, &tid);
  1469.             
  1470.                 if (m_rgpthreads)
  1471.                 {
  1472.                     unsigned i;
  1473.                     for (i = 0; i < m_nthreads; i++)
  1474.                     {
  1475.                         pThread = m_rgpthreads[i];
  1476.                         if (pThread->vmid == vmid || pThread->tid == tid)
  1477.                         {
  1478.                             m_nthreads--;
  1479.                             m_rgpthreads[i] = m_rgpthreads[m_nthreads];
  1480.                             break;
  1481.                         }
  1482.                     }
  1483.                 }
  1484.             }
  1485.             LeaveCriticalSection(&m_ThreadEventCS);
  1486.  
  1487.             if (g_ProfOptions & OPT_VERBOSE)
  1488.             {
  1489.                 if (pThread)
  1490.                     WriteOutputFmt("Thread %x destroyed\n", pThread->tid);
  1491.                 else
  1492.                     WriteOutput("Thread destroyed\n");
  1493.             }
  1494.  
  1495.             if (pThread)
  1496.                 delete pThread;
  1497.  
  1498.             break;
  1499.  
  1500.         case JVM_EVENT_TYPE_CLASS_LOAD_STARTED:     // A class is being loaded (PSTR)
  1501.             if (g_ProfOptions & OPT_VERBOSE)
  1502.                 WriteOutputLongFmt("Loading class %s...\n", (PCSTR)event_id);
  1503.             break;
  1504.  
  1505.         case JVM_EVENT_TYPE_CLASS_LOAD_FAILED:      // A class failed to load (PSTR).
  1506.             if (g_ProfOptions & OPT_VERBOSE)
  1507.                 WriteOutputLongFmt("Failed to load class %s.\n", (PCSTR)event_id);
  1508.             break;
  1509.  
  1510.         case JVM_EVENT_TYPE_CLASS_LOAD_FINISHED:    // A class has been loaded (ClassID)
  1511.  
  1512.             if (m_VMRelease > VM_IE40)
  1513.             {
  1514.                 PSTR pszClassUtf8 = NULL;
  1515.                 int ncMethods;
  1516.                 MethodID *pmethodid = NULL;
  1517.  
  1518.                 BOOL fNeedClassName = (g_ProfOptions & OPT_VERBOSE) || g_nClassesToHook;
  1519.  
  1520.                 hr = m_monitor_info->ClassInformation(
  1521.                         (ClassID)event_id,
  1522.                         fNeedClassName ? &pszClassUtf8 : NULL,
  1523.                         NULL,
  1524.                         &ncMethods,
  1525.                         g_nMethodsToHook ? &pmethodid : NULL,
  1526.                         NULL);
  1527.  
  1528.                 if (SUCCEEDED(hr))
  1529.                 {
  1530.                     PSTR pszClass = pszClassUtf8;
  1531.                     PSTR pszClassAnsi;
  1532.                     if (Utf8ToAnsi(pszClassUtf8, &pszClassAnsi))
  1533.                     {
  1534.                         if (pszClassAnsi)
  1535.                             pszClass = pszClassAnsi;
  1536.                             
  1537.                         if (g_ProfOptions & OPT_VERBOSE)
  1538.                             WriteOutputLongFmt("Class %s successfully loaded.\n", pszClass);
  1539.  
  1540.                         if (g_nClassesToHook)
  1541.                         {
  1542.                             ULONG iPattern;
  1543.  
  1544.                             for (iPattern = 0; iPattern < g_nClassesToHook; iPattern++)
  1545.                             {
  1546.                                 if (match(g_rgpszClassesToHook[iPattern], pszClass))
  1547.                                 {
  1548.                                     m_monitor_info3->EnableMethodCallEvents(
  1549.                                             (ClassID)event_id,
  1550.                                             JVM_ID_CLASS,
  1551.                                             JVM_PERMIT_METHOD_CALL_EVENTS);
  1552.                                     ncMethods = 0;
  1553.                                     break;
  1554.                                 }
  1555.                             }
  1556.                         }
  1557.  
  1558.                         if (pszClassAnsi)
  1559.                             delete pszClassAnsi;
  1560.                     }
  1561.  
  1562.                     CoTaskMemFree(pszClassUtf8);
  1563.  
  1564.                     if (pmethodid)
  1565.                     {
  1566.                         ULONG iMethod;
  1567.  
  1568.                         for (iMethod = 0; iMethod < ncMethods; iMethod++)
  1569.                         {
  1570.                             PSTR pszMethodUtf8;
  1571.                             if (SUCCEEDED(m_monitor_info->MethodInformation(pmethodid[iMethod], &pszMethodUtf8, NULL, NULL, NULL, NULL)))
  1572.                             {
  1573.                                 PSTR pszMethod = pszMethodUtf8;
  1574.                                 PSTR pszMethodAnsi;
  1575.                                 if (Utf8ToAnsi(pszMethodUtf8, &pszMethodAnsi))
  1576.                                 {
  1577.                                     if (pszMethodAnsi)
  1578.                                         pszMethod = pszMethodAnsi;
  1579.  
  1580.                                     ULONG iPattern;
  1581.  
  1582.                                     for (iPattern = 0; iPattern < g_nMethodsToHook; iPattern++)
  1583.                                     {
  1584.                                         if (match(g_rgpszMethodsToHook[iPattern], pszMethod))
  1585.                                         {
  1586.                                             m_monitor_info3->EnableMethodCallEvents(
  1587.                                                     pmethodid[iMethod],
  1588.                                                     JVM_ID_METHOD,
  1589.                                                     JVM_PERMIT_METHOD_CALL_EVENTS);
  1590.                                             break;
  1591.                                         }
  1592.                                     }
  1593.  
  1594.                                     if (pszMethodAnsi)
  1595.                                         delete pszMethodAnsi;
  1596.                                 }
  1597.  
  1598.                                 CoTaskMemFree(pszMethodUtf8);
  1599.                             }
  1600.                         }
  1601.  
  1602.                         CoTaskMemFree(pmethodid);
  1603.                     }
  1604.                 }
  1605.             }
  1606.             else
  1607.             {
  1608.                 // Sorry.  The IE4 VM provided a PCSTR instead of a ClassID.
  1609.  
  1610.                 if (g_ProfOptions & OPT_VERBOSE)
  1611.                     WriteOutputLongFmt("Class %s successfully loaded.\n", (PCSTR)event_id);
  1612.             }
  1613.             
  1614.             break;
  1615.  
  1616.         case JVM_EVENT_TYPE_CLASS_UNLOAD:           // A class has been unloaded (ClassID)
  1617.         {
  1618.             if (m_VMRelease > VM_IE40)
  1619.             {
  1620.                 // BUGBUG: remove any references to the unloading class, cache any info needed
  1621.  
  1622.                 PSTR pszClassUtf8;
  1623.  
  1624.                 hr = m_monitor_info->ClassInformation(event_id, &pszClassUtf8, NULL, NULL, NULL, NULL);
  1625.  
  1626.                 if (hr == S_OK)
  1627.                 {
  1628.                     if (g_ProfOptions & OPT_VERBOSE)
  1629.                     {
  1630.                         WriteOutput("Class ");
  1631.                         WriteOutputUtf8(pszClassUtf8);
  1632.                         WriteOutput(" unloaded.\n");
  1633.                     }
  1634.  
  1635.                     CoTaskMemFree(pszClassUtf8);
  1636.                 }
  1637.             }
  1638.             else
  1639.             {
  1640.                 // Sorry.  The IE4 VM provided a PCSTR instead of a ClassID.
  1641.  
  1642.                 if (g_ProfOptions & OPT_VERBOSE)
  1643.                     WriteOutputLongFmt("Class %s unloaded.\n", (PCSTR)event_id);
  1644.             }
  1645.  
  1646.             break;
  1647.         }
  1648.  
  1649.         case JVM_EVENT_TYPE_GC_STARTED:         // The garbage collector started (no ID)
  1650.             m_gcprof.GCStarted();
  1651.             break;
  1652.  
  1653.         case JVM_EVENT_TYPE_GC_FINISHED:        // The garbage collector stopped (no ID)
  1654.             if (g_ProfOptions & OPT_VERBOSE)
  1655.                 WriteOutput("Garbage collection occurred.\n");
  1656.             m_gcprof.GCFinished();
  1657.             m_allocprof.GCOccurred();
  1658.             break;
  1659.  
  1660.         case JVM_EVENT_TYPE_SHUTDOWN:           // Program exiting (no ID).
  1661.             ShutdownWorker(TRUE);
  1662.             break;
  1663.  
  1664.         default:
  1665.             // What is this?
  1666.             break;
  1667.     }
  1668.  
  1669.     return S_OK;
  1670. }
  1671.  
  1672.  
  1673. STDMETHODIMP EventMonitor::MethodEntry (MethodID method_id, StackID stack_id)
  1674. {
  1675.     ThreadRecord *pThread = GetCurrentThreadRecord();
  1676.     if (pThread)
  1677.     {
  1678.         m_calltracer.OnEnterMethod(pThread, method_id, stack_id);
  1679.  
  1680.         m_callprof.EnterMethod(pThread, method_id);
  1681.     }
  1682.  
  1683.     return S_OK;
  1684. }
  1685.  
  1686.  
  1687. STDMETHODIMP EventMonitor::MethodExit(StackID stack_id)
  1688. {
  1689.     ThreadRecord *pThread = GetCurrentThreadRecord();
  1690.     if (pThread)
  1691.     {
  1692.         m_callprof.ExitMethod(pThread);
  1693.  
  1694.         m_calltracer.OnMethodExit(pThread, NULL, stack_id);
  1695.     }
  1696.  
  1697.     return S_OK;
  1698. }
  1699.  
  1700.  
  1701. STDMETHODIMP EventMonitor::ExecuteByteCode(MethodID method_id, BYTE_CODE *pbyte_code, DWORD byte_code_offset)
  1702. {
  1703.     return S_OK;
  1704. }
  1705.  
  1706.  
  1707. STDMETHODIMP EventMonitor::ExecuteSourceLine(MethodID method_id, DWORD line_number)
  1708. {
  1709.     return(S_OK);
  1710. }
  1711.  
  1712.  
  1713. STDMETHODIMP EventMonitor::NotifyEvent2(JVM_EVENT_TYPE2 event2, UniqueID first_event_id, UniqueID second_event_id)
  1714. {
  1715.     HRESULT hr = S_OK;
  1716.  
  1717.     switch (event2)
  1718.     {
  1719.     ThreadRecord *pThread;
  1720.  
  1721.     // A thread's name has been set.  ID1 is ThreadID.  ID2 is pointer to Unicode string thread name.
  1722.     case JVM_EVENT_TYPE2_THREAD_SET_NAME:
  1723.         if (g_ProfOptions & OPT_VERBOSE)
  1724.         {
  1725.             ThreadID vmid = (ThreadID)first_event_id;
  1726.             PCWSTR newname = (PCWSTR)second_event_id;
  1727.  
  1728.             if (m_monitor_info2)
  1729.             {
  1730.                 DWORD tid;
  1731.                 if (SUCCEEDED(m_monitor_info2->ThreadInformation(vmid, &tid)))
  1732.                 {
  1733.                     WriteOutputFmt("Thread %x's name changed to \"", tid);
  1734.                     WriteOutputW(newname);
  1735.                     WriteOutput("\".\n");
  1736.                 }
  1737.             }
  1738.         }
  1739.         break;
  1740.  
  1741.     // An exception is about to be thrown.  ID1 is the ClassID of the exception, ID2 is the ObjectID of the exception.
  1742.     case JVM_EVENT_TYPE2_EXCEPTION_THROWN:
  1743.         pThread = GetCurrentThreadRecord();
  1744.         if (pThread)
  1745.             m_callprof.ExceptionThrown(pThread);
  1746.  
  1747.         if (g_ProfOptions & OPT_VERBOSE)
  1748.         {
  1749.             PSTR pszExceptionUtf8;
  1750.             if (SUCCEEDED(m_monitor_info->ClassInformation((ClassID)first_event_id, &pszExceptionUtf8, NULL, NULL, NULL, NULL)))
  1751.             {
  1752.                 WriteOutput("Exception ");
  1753.                 WriteOutputUtf8(pszExceptionUtf8);
  1754.                 WriteOutput(" \n");
  1755.  
  1756.                 CoTaskMemFree(pszExceptionUtf8);
  1757.             }
  1758.         }
  1759.  
  1760.         break;
  1761.  
  1762.     // An exception occurred.  ID1 is MethodID, ID2 is StackID.  The exception handler will be executed in MethodID/StackID's stack frame.
  1763.     case JVM_EVENT_TYPE2_EXCEPTION_OCCURRED:
  1764.         pThread = GetCurrentThreadRecord();
  1765.         if (pThread)
  1766.             m_callprof.ResumeMethod(pThread, (MethodID)first_event_id);
  1767.         break;
  1768.  
  1769.     // Callback from GetStackTrace.  ID1 is MethodID, ID2 is StackID.
  1770.     case JVM_EVENT_TYPE2_STACK_TRACE:
  1771.         pThread = GetCurrentThreadRecord();
  1772.         pThread->allocdata.idCreatingMethod = (MethodID)first_event_id;
  1773.         hr = S_FALSE;
  1774.         break;
  1775.  
  1776.     // The vm has fully initialized.
  1777.     case JVM_EVENT_TYPE2_INITIALIZED:
  1778.         OnVMInitialization();
  1779.         break;
  1780.  
  1781.     // All event monitors have initialized.  ID1 is the number of event monitors
  1782.     // attached to the VM. ID2 is a bitmask of JAVA_EVENT_CATEGORY, indicating the
  1783.     // maximum possible set of events that may be enabled by all attached profilers.
  1784.     case JVM_EVENT_TYPE2_MONITORS_INITIALIZED:
  1785.  
  1786.         unsigned nmonitors;
  1787.         nmonitors = (unsigned)first_event_id;
  1788.  
  1789.         if (nmonitors > 1)
  1790.             WriteOutputFmt("%u other profilers are attached.\n", nmonitors-1);
  1791.  
  1792.         if (g_ProfOptions & OPT_VERBOSE)
  1793.         {
  1794.             DWORD possible_events = (DWORD)second_event_id;
  1795.  
  1796. #if 0                
  1797.             Spew(SPEW_REG, "%u monitors, possible events:", nmonitors);
  1798.             SpewCategories(SPEW_REG, possible_events);
  1799.             Spew(SPEW_REG, "\n");
  1800. #endif
  1801.  
  1802.         }
  1803.  
  1804.         if (m_monitor_info4 != NULL)
  1805.         {
  1806.             DWORD initopts;
  1807.             hr = m_monitor_info4->GetFinalInitializationOptions(&initopts);
  1808.             if (hr == S_OK)
  1809.             {
  1810. #if 0                
  1811.                 Spew(SPEW_REG, "final initialization options:");
  1812.                 SpewInitOptions(SPEW_REG, initopts);
  1813.                 Spew(SPEW_REG, "\n");
  1814. #endif
  1815.             }
  1816.         }
  1817.  
  1818.         break;
  1819.     }
  1820.  
  1821.     return(hr);
  1822. }
  1823.  
  1824.  
  1825. STDMETHODIMP EventMonitor::MethodExit2(MethodID method_id, StackID stack_id)
  1826. {
  1827.     ThreadRecord *pThread = GetCurrentThreadRecord();
  1828.     if (pThread)
  1829.     {
  1830.         m_callprof.ExitMethod(pThread);
  1831.  
  1832.         m_calltracer.OnMethodExit(pThread, method_id, stack_id);
  1833.  
  1834.         m_callprof.ResumeMethod(pThread, method_id);
  1835.     }
  1836.  
  1837.     return S_OK;
  1838. }
  1839.  
  1840.  
  1841. STDMETHODIMP EventMonitor::GetPossibleEventCategories (DWORD *ppossible_events)
  1842. {
  1843.     // We don't toggle any events.
  1844.     return m_monitor_info->GetEventMask(ppossible_events);
  1845. }
  1846.  
  1847.  
  1848. //------------------------------------------------------------------------
  1849.  
  1850.  
  1851. STDMETHODIMP EventMonitor::OnObjectAllocated (ObjectID idObject, ClassID idType)
  1852. {
  1853.     DWORD size = 0;
  1854.     if (m_monitor_info2 != NULL)
  1855.         if (m_monitor_info2->GetObjectSize(idObject, &size) != S_OK)
  1856.             size = 0;
  1857.  
  1858.     MethodID idCreatingMethod = NULL;
  1859.     if (g_ProfOptions & OPT_ALLOC_PER_METHOD)
  1860.     {
  1861.         ThreadRecord *pThread = GetCurrentThreadRecord();
  1862.         if (pThread != NULL)
  1863.         {
  1864.             if (g_ProfOptions & OPT_PROF_CALLS)
  1865.             {
  1866.                 // If there is no current entry, then the allocation occurred
  1867.                 // in native code.  (For example, the VM performs allocations
  1868.                 // during initialization, before any methods are called.)
  1869.                 CallProfiler::CallProfilerEntry *pent = pThread->calldata.pentCurMethod;
  1870.                 if (pent)
  1871.                     idCreatingMethod = pent->id;
  1872.             }
  1873.             else
  1874.             {
  1875.                 pThread->allocdata.idCreatingMethod = NULL;
  1876.                 m_monitor_info2->GetStackTrace(NULL);
  1877.                 idCreatingMethod = pThread->allocdata.idCreatingMethod;
  1878.             }
  1879.         }
  1880.     }
  1881.  
  1882.     m_allocprof.InstanceCreated(idType, size, idCreatingMethod);
  1883.  
  1884.     return S_OK;
  1885. }
  1886.  
  1887.