Bug 673631 - Clean up probes and register (almost) all profiler control entry points in JS_DefineProfilingFunctions (r=luke,waldo,jst)
authorSteve Fink <sfink@mozilla.com>
Tue, 26 Jul 2011 15:56:09 -0700
changeset 75342 5b1e885539a5f17f1f4afb58fc459faf4c9e5dba
parent 75341 4d9fe0a94ba2460358cf7f65ffa0f0d517b35c6a
child 75343 4d046f0cdcbd241bcdd4dc7d7cacee1e4fde7da9
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersluke, waldo, jst
bugs673631
milestone8.0a1
Bug 673631 - Clean up probes and register (almost) all profiler control entry points in JS_DefineProfilingFunctions (r=luke,waldo,jst) Previously, JS_DefineProfilingFunctions only defined a very basic set of functions (startProfiling and stopProfiling), and various scattered places added more specific ones (start/stop vtune, dumpProfile, etc.) This patch makes jsdbgapi do all of it, so that all users get the same set. Also rename JS_DumpProfile -> JS_DumpBytecode to avoid name conflict. The bytecode dumps are how the counters ("profiles") are displayed, so the DumpProfile name was bogus anyway.
dom/base/nsJSEnvironment.cpp
ipc/testshell/XPCShellEnvironment.cpp
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsgc.cpp
js/src/jsprobes.cpp
js/src/jsprobes.h
js/src/shell/js.cpp
js/src/xpconnect/loader/mozJSComponentLoader.cpp
js/src/xpconnect/shell/xpcshell.cpp
xpcom/tests/TestHarness.h
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2958,35 +2958,16 @@ NS_JProfStopProfiling()
 static JSFunctionSpec JProfFunctions[] = {
     {"JProfStartProfiling",        JProfStartProfilingJS,      0, 0},
     {"JProfStopProfiling",         JProfStopProfilingJS,       0, 0},
     {nsnull,                       nsnull,                     0, 0}
 };
 
 #endif /* defined(MOZ_JPROF) */
 
-#ifdef MOZ_CALLGRIND
-static JSFunctionSpec CallgrindFunctions[] = {
-    {"startCallgrind",             js_StartCallgrind,          0, 0},
-    {"stopCallgrind",              js_StopCallgrind,           0, 0},
-    {"dumpCallgrind",              js_DumpCallgrind,           1, 0},
-    {nsnull,                       nsnull,                     0, 0}
-};
-#endif
-
-#ifdef MOZ_VTUNE
-static JSFunctionSpec VtuneFunctions[] = {
-    {"startVtune",                 js_StartVtune,              1, 0},
-    {"stopVtune",                  js_StopVtune,               0, 0},
-    {"pauseVtune",                 js_PauseVtune,              0, 0},
-    {"resumeVtune",                js_ResumeVtune,             0, 0},
-    {nsnull,                       nsnull,                     0, 0}
-};
-#endif
-
 #ifdef MOZ_TRACEVIS
 static JSFunctionSpec EthogramFunctions[] = {
     {"initEthogram",               js_InitEthogram,            0, 0},
     {"shutdownEthogram",           js_ShutdownEthogram,        0, 0},
     {nsnull,                       nsnull,                     0, 0}
 };
 #endif
 
@@ -3012,26 +2993,16 @@ nsJSContext::InitClasses(void *aGlobalOb
   ::JS_DefineFunctions(mContext, globalObj, TraceMallocFunctions);
 #endif
 
 #ifdef MOZ_JPROF
   // Attempt to initialize JProf functions
   ::JS_DefineFunctions(mContext, globalObj, JProfFunctions);
 #endif
 
-#ifdef MOZ_CALLGRIND
-  // Attempt to initialize Callgrind functions
-  ::JS_DefineFunctions(mContext, globalObj, CallgrindFunctions);
-#endif
-
-#ifdef MOZ_VTUNE
-  // Attempt to initialize Vtune functions
-  ::JS_DefineFunctions(mContext, globalObj, VtuneFunctions);
-#endif
-
 #ifdef MOZ_TRACEVIS
   // Attempt to initialize Ethogram functions
   ::JS_DefineFunctions(mContext, globalObj, EthogramFunctions);
 #endif
 
   JSOptionChangedCallback(js_options_dot_str, this);
 
   return rv;
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -554,21 +554,16 @@ JSFunctionSpec gGlobalFunctions[] =
     {"gc",              GC,             0,0},
 #ifdef JS_GC_ZEAL
     {"gczeal",          GCZeal,         1,0},
 #endif
     {"clear",           Clear,          1,0},
 #ifdef DEBUG
     {"dumpHeap",        DumpHeap,       5,0},
 #endif
-#ifdef MOZ_CALLGRIND
-    {"startCallgrind",  js_StartCallgrind,  0,0},
-    {"stopCallgrind",   js_StopCallgrind,   0,0},
-    {"dumpCallgrind",   js_DumpCallgrind,   1,0},
-#endif
     {nsnull,nsnull,0,0}
 };
 
 typedef enum JSShellErrNum
 {
 #define MSG_DEF(name, number, count, exception, format) \
     name = number,
 #include "jsshell.msg"
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -38,16 +38,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS debugging API.
  */
 #include <string.h>
+#include <stdarg.h>
 #include "jsprvtd.h"
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
 #include "jsclist.h"
 #include "jshashtable.h"
 #include "jsapi.h"
 #include "jscntxt.h"
@@ -78,16 +79,20 @@
 
 #include "vm/Stack-inl.h"
 
 #include "jsautooplen.h"
 
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Retcon.h"
 
+#ifdef __APPLE__
+#include "sharkctl.h"
+#endif
+
 using namespace js;
 using namespace js::gc;
 
 JS_PUBLIC_API(JSBool)
 JS_GetDebugMode(JSContext *cx)
 {
     return cx->compartment->debugMode();
 }
@@ -1208,66 +1213,364 @@ JS_SetContextDebugHooks(JSContext *cx, c
 }
 
 JS_PUBLIC_API(JSDebugHooks *)
 JS_ClearContextDebugHooks(JSContext *cx)
 {
     return JS_SetContextDebugHooks(cx, &js_NullDebugHooks);
 }
 
+/************************************************************************/
+
+/* Profiling-related API */
+
+/* Thread-unsafe error management */
+
+static char gLastError[2000];
+
+static void
+#ifdef _GNU_SOURCE
+__attribute__((unused,format(printf,1,2)))
+#endif
+UnsafeError(const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    (void) vsnprintf(gLastError, sizeof(gLastError), format, args);
+    va_end(args);
+
+    gLastError[sizeof(gLastError) - 1] = '\0';
+}
+
+JS_PUBLIC_API(const char *)
+JS_UnsafeGetLastProfilingError()
+{
+    return gLastError;
+}
+
 JS_PUBLIC_API(JSBool)
-JS_StartProfiling()
+JS_StartProfiling(const char *profileName)
 {
-    return Probes::startProfiling();
+    JSBool ok = JS_TRUE;
+#if defined(MOZ_SHARK) && defined(__APPLE__)
+    if (!Shark::Start()) {
+        UnsafeError("Failed to start Shark for %s", profileName);
+        ok = JS_FALSE;
+    }
+#endif
+#ifdef MOZ_VTUNE
+    if (!js_StartVtune(profileName))
+        ok = JS_FALSE;
+#endif
+    return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_StopProfiling(const char *profileName)
+{
+    JSBool ok = JS_TRUE;
+#if defined(MOZ_SHARK) && defined(__APPLE__)
+    Shark::Stop();
+#endif
+#ifdef MOZ_VTUNE
+    if (!js_StopVtune())
+        ok = JS_FALSE;
+#endif
+    return ok;
 }
 
-JS_PUBLIC_API(void)
-JS_StopProfiling()
+/*
+ * Start or stop whatever platform- and configuration-specific profiling
+ * backends are available.
+ */
+static JSBool
+ControlProfilers(bool toState)
 {
-    Probes::stopProfiling();
+    JSBool ok = JS_TRUE;
+
+    if (! Probes::ProfilingActive && toState) {
+#if defined(MOZ_SHARK) && defined(__APPLE__)
+        if (!Shark::Start()) {
+            UnsafeError("Failed to start Shark");
+            ok = JS_FALSE;
+        }
+#endif
+#ifdef MOZ_CALLGRIND
+        if (! js_StartCallgrind()) {
+            UnsafeError("Failed to start Callgrind");
+            ok = JS_FALSE;
+        }
+#endif
+#ifdef MOZ_VTUNE
+        if (! js_ResumeVtune())
+            ok = JS_FALSE;
+#endif
+    } else if (Probes::ProfilingActive && ! toState) {
+#if defined(MOZ_SHARK) && defined(__APPLE__)
+        Shark::Stop();
+#endif
+#ifdef MOZ_CALLGRIND
+        if (! js_StopCallgrind()) {
+            UnsafeError("failed to stop Callgrind");
+            ok = JS_FALSE;
+        }
+#endif
+#ifdef MOZ_VTUNE
+        if (! js_PauseVtune())
+            ok = JS_FALSE;
+#endif
+    }
+
+    Probes::ProfilingActive = toState;
+
+    return ok;
+}
+
+/*
+ * Pause/resume whatever profiling mechanism is currently compiled
+ * in, if applicable. This will not affect things like dtrace.
+ *
+ * Do not mix calls to these APIs with calls to the individual
+ * profilers' pause/resume functions, because only overall state is
+ * tracked, not the state of each profiler.
+ */
+JS_PUBLIC_API(JSBool)
+JS_PauseProfilers(const char *profileName)
+{
+    return ControlProfilers(false);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ResumeProfilers(const char *profileName)
+{
+    return ControlProfilers(true);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DumpProfile(const char *outfile, const char *profileName)
+{
+    JSBool ok = JS_TRUE;
+#ifdef MOZ_CALLGRIND
+    js_DumpCallgrind(outfile);
+#endif
+    return ok;
 }
 
 #ifdef MOZ_PROFILING
 
+struct RequiredStringArg {
+    JSContext *mCx;
+    char *mBytes;
+    RequiredStringArg(JSContext *cx, uintN argc, jsval *vp, size_t argi, const char *caller)
+        : mCx(cx), mBytes(NULL)
+    {
+        if (argc <= argi) {
+            JS_ReportError(cx, "%s: not enough arguments", caller);
+        } else if (!JSVAL_IS_STRING(JS_ARGV(cx, vp)[argi])) {
+            JS_ReportError(cx, "%s: invalid arguments (string expected)", caller);
+        } else {
+            mBytes = JS_EncodeString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[argi]));
+        }
+    }
+    operator void*() {
+        return (void*) mBytes;
+    }
+    ~RequiredStringArg() {
+        if (mBytes)
+            mCx->free_(mBytes);
+    }
+};
+
 static JSBool
 StartProfiling(JSContext *cx, uintN argc, jsval *vp)
 {
-    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling()));
-    return true;
+    if (argc == 0) {
+        JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(NULL)));
+        return JS_TRUE;
+    }
+
+    RequiredStringArg profileName(cx, argc, vp, 0, "startProfiling");
+    if (!profileName)
+        return JS_FALSE;
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(profileName.mBytes)));
+    return JS_TRUE;
 }
 
 static JSBool
 StopProfiling(JSContext *cx, uintN argc, jsval *vp)
 {
-    JS_StopProfiling();
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    if (argc == 0) {
+        JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(NULL)));
+        return JS_TRUE;
+    }
+
+    RequiredStringArg profileName(cx, argc, vp, 0, "stopProfiling");
+    if (!profileName)
+        return JS_FALSE;
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(profileName.mBytes)));
+    return JS_TRUE;
+}
+
+static JSBool
+PauseProfilers(JSContext *cx, uintN argc, jsval *vp)
+{
+    if (argc == 0) {
+        JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(NULL)));
+        return JS_TRUE;
+    }
+
+    RequiredStringArg profileName(cx, argc, vp, 0, "pauseProfiling");
+    if (!profileName)
+        return JS_FALSE;
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(profileName.mBytes)));
+    return JS_TRUE;
+}
+
+static JSBool
+ResumeProfilers(JSContext *cx, uintN argc, jsval *vp)
+{
+    if (argc == 0) {
+        JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(NULL)));
+        return JS_TRUE;
+    }
+
+    RequiredStringArg profileName(cx, argc, vp, 0, "resumeProfiling");
+    if (!profileName)
+        return JS_FALSE;
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(profileName.mBytes)));
+    return JS_TRUE;
+}
+
+/* Usage: DumpProfile([filename[, profileName]]) */
+static JSBool
+DumpProfile(JSContext *cx, uintN argc, jsval *vp)
+{
+    bool ret;
+    if (argc == 0) {
+        ret = JS_DumpProfile(NULL, NULL);
+    } else {
+        RequiredStringArg filename(cx, argc, vp, 0, "dumpProfile");
+        if (!filename)
+            return JS_FALSE;
+
+        if (argc == 1) {
+            ret = JS_DumpProfile(filename.mBytes, NULL);
+        } else {
+            RequiredStringArg profileName(cx, argc, vp, 1, "dumpProfile");
+            if (!profileName)
+                return JS_FALSE;
+
+            ret = JS_DumpProfile(filename.mBytes, profileName.mBytes);
+        }
+    }
+
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(ret));
     return true;
 }
 
 #ifdef MOZ_SHARK
 
 static JSBool
 IgnoreAndReturnTrue(JSContext *cx, uintN argc, jsval *vp)
 {
     JS_SET_RVAL(cx, vp, JSVAL_TRUE);
     return true;
 }
 
 #endif
 
+#ifdef MOZ_CALLGRIND
+static JSBool
+StartCallgrind(JSContext *cx, uintN argc, jsval *vp)
+{
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartCallgrind()));
+    return JS_TRUE;
+}
+
+static JSBool
+StopCallgrind(JSContext *cx, uintN argc, jsval *vp)
+{
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopCallgrind()));
+    return JS_TRUE;
+}
+
+static JSBool
+DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
+{
+    if (argc == 0) {
+        JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(NULL)));
+        return JS_TRUE;
+    }
+
+    RequiredStringArg outFile(cx, argc, vp, 0, "dumpCallgrind");
+    if (!outFile)
+        return JS_FALSE;
+
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(outFile.mBytes)));
+    return JS_TRUE;
+}    
+#endif
+
+#ifdef MOZ_VTUNE
+static JSBool
+StartVtune(JSContext *cx, uintN argc, jsval *vp)
+{
+    RequiredStringArg profileName(cx, argc, vp, 0, "startVtune");
+    if (!profileName)
+        return JS_FALSE;
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartVtune(profileName.mBytes)));
+    return JS_TRUE;
+}
+
+static JSBool
+StopVtune(JSContext *cx, uintN argc, jsval *vp)
+{
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopVtune()));
+    return JS_TRUE;
+}
+
+static JSBool
+PauseVtune(JSContext *cx, uintN argc, jsval *vp)
+{
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_PauseVtune()));
+    return JS_TRUE;
+}
+
+static JSBool
+ResumeVtune(JSContext *cx, uintN argc, jsval *vp)
+{
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_ResumeVtune()));
+    return JS_TRUE;
+}
+#endif
+
 static JSFunctionSpec profiling_functions[] = {
-    JS_FN("startProfiling",  StartProfiling,      0,0),
-    JS_FN("stopProfiling",   StopProfiling,       0,0),
+    JS_FN("startProfiling",  StartProfiling,      1,0),
+    JS_FN("stopProfiling",   StopProfiling,       1,0),
+    JS_FN("pauseProfilers",  PauseProfilers,      1,0),
+    JS_FN("resumeProfilers", ResumeProfilers,     1,0),
+    JS_FN("dumpProfile",     DumpProfile,         2,0),
 #ifdef MOZ_SHARK
     /* Keep users of the old shark API happy. */
     JS_FN("connectShark",    IgnoreAndReturnTrue, 0,0),
     JS_FN("disconnectShark", IgnoreAndReturnTrue, 0,0),
     JS_FN("startShark",      StartProfiling,      0,0),
     JS_FN("stopShark",       StopProfiling,       0,0),
 #endif
+#ifdef MOZ_CALLGRIND
+    JS_FN("startCallgrind", StartCallgrind,       0,0),
+    JS_FN("stopCallgrind",  StopCallgrind,        0,0),
+    JS_FN("dumpCallgrind",  DumpCallgrind,        1,0),
+#endif
+#ifdef MOZ_VTUNE
+    JS_FN("startVtune",     js_StartVtune,        1,0),
+    JS_FN("stopVtune",      js_StopVtune,         0,0),
+    JS_FN("pauseVtune",     js_PauseVtune,        0,0),
+    JS_FN("resumeVtune",    js_ResumeVtune,       0,0),
+#endif
     JS_FS_END
 };
 
 #endif
 
 JS_PUBLIC_API(JSBool)
 JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj)
 {
@@ -1279,50 +1582,40 @@ JS_DefineProfilingFunctions(JSContext *c
 #endif
 }
 
 #ifdef MOZ_CALLGRIND
 
 #include <valgrind/callgrind.h>
 
 JS_FRIEND_API(JSBool)
-js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp)
+js_StartCallgrind()
 {
     CALLGRIND_START_INSTRUMENTATION;
     CALLGRIND_ZERO_STATS;
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
-    return JS_TRUE;
-}
-
-JS_FRIEND_API(JSBool)
-js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp)
-{
-    CALLGRIND_STOP_INSTRUMENTATION;
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
-    return JS_TRUE;
+    return true;
 }
 
 JS_FRIEND_API(JSBool)
-js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
+js_StopCallgrind()
 {
-    JSString *str;
+    CALLGRIND_STOP_INSTRUMENTATION;
+    return true;
+}
 
-    jsval *argv = JS_ARGV(cx, vp);
-    if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
-        str = JSVAL_TO_STRING(argv[0]);
-        JSAutoByteString bytes(cx, str);
-        if (!!bytes) {
-            CALLGRIND_DUMP_STATS_AT(bytes.ptr());
-            return JS_TRUE;
-        }
+JS_FRIEND_API(JSBool)
+js_DumpCallgrind(const char *outfile)
+{
+    if (outfile) {
+        CALLGRIND_DUMP_STATS_AT(outfile);
+    } else {
+        CALLGRIND_DUMP_STATS;
     }
-    CALLGRIND_DUMP_STATS;
 
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
-    return JS_TRUE;
+    return true;
 }
 
 #endif /* MOZ_CALLGRIND */
 
 #ifdef MOZ_VTUNE
 #include <VTuneApi.h>
 
 static const char *vtuneErrorMessages[] = {
@@ -1347,18 +1640,18 @@ static const char *vtuneErrorMessages[] 
   "invalid 'event size' field",
   "sampling file already bound",
   "invalid event path",
   "invalid license",
   "invalid 'global options' field",
 
 };
 
-JS_FRIEND_API(JSBool)
-js_StartVtune(JSContext *cx, uintN argc, jsval *vp)
+bool
+js_StartVtune(const char *profileName)
 {
     VTUNE_EVENT events[] = {
         { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
         { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
     };
 
     U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT);
     char *default_filename = "mozilla-vtune.tb5";
@@ -1375,72 +1668,64 @@ js_StartVtune(JSContext *cx, uintN argc,
         0.1,  /* Sampling interval in ms */
         1,    /* 1 for event-based sampling, 0 for time-based */
 
         n_events,
         events,
         default_filename,
     };
 
-    jsval *argv = JS_ARGV(cx, vp);
-    if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
-        str = JSVAL_TO_STRING(argv[0]);
-        params.tb5Filename = DeflateString(cx, str->chars(), str->length());
+    if (profileName) {
+        char filename[strlen(profileName) + strlen("-vtune.tb5") + 1];
+        snprintf(filename, sizeof(filename), "%s-vtune.tb5", profileName);
+        params.tb5Filename = filename;
     }
 
     status = VTStartSampling(&params);
 
     if (params.tb5Filename != default_filename)
-        cx->free_(params.tb5Filename);
+        Foreground::free_(params.tb5Filename);
 
     if (status != 0) {
         if (status == VTAPI_MULTIPLE_RUNS)
             VTStopSampling(0);
         if (status < sizeof(vtuneErrorMessages))
-            JS_ReportError(cx, "Vtune setup error: %s",
-                           vtuneErrorMessages[status]);
+            UnsafeError("Vtune setup error: %s", vtuneErrorMessages[status]);
         else
-            JS_ReportError(cx, "Vtune setup error: %d",
-                           status);
+            UnsafeError("Vtune setup error: %d", status);
         return false;
     }
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
-JS_FRIEND_API(JSBool)
-js_StopVtune(JSContext *cx, uintN argc, jsval *vp)
+bool
+js_StopVtune()
 {
     U32 status = VTStopSampling(1);
     if (status) {
         if (status < sizeof(vtuneErrorMessages))
-            JS_ReportError(cx, "Vtune shutdown error: %s",
-                           vtuneErrorMessages[status]);
+            UnsafeError("Vtune shutdown error: %s", vtuneErrorMessages[status]);
         else
-            JS_ReportError(cx, "Vtune shutdown error: %d",
-                           status);
+            UnsafeError("Vtune shutdown error: %d", status);
         return false;
     }
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
-JS_FRIEND_API(JSBool)
-js_PauseVtune(JSContext *cx, uintN argc, jsval *vp)
+bool
+js_PauseVtune()
 {
     VTPause();
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
-JS_FRIEND_API(JSBool)
-js_ResumeVtune(JSContext *cx, uintN argc, jsval *vp)
+bool
+js_ResumeVtune()
 {
     VTResume();
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
 #endif /* MOZ_VTUNE */
 
 #ifdef MOZ_TRACEVIS
 /*
  * Ethogram - Javascript wrapper for TraceVis state
@@ -1901,37 +2186,34 @@ JS_PUBLIC_API(JSFunctionCallback)
 JS_GetFunctionCallback(JSContext *cx)
 {
     return cx->functionCallback;
 }
 
 #endif /* MOZ_TRACE_JSCALLS */
 
 JS_PUBLIC_API(void)
-JS_DumpProfile(JSContext *cx, JSScript *script)
+JS_DumpBytecode(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(!cx->runtime->gcRunning);
 
 #if defined(DEBUG)
-    if (script->pcCounters) {
-        // Display hit counts for every JS code line
-        AutoArenaAllocator mark(&cx->tempPool);
-        Sprinter sprinter;
-        INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
+    AutoArenaAllocator mark(&cx->tempPool);
+    Sprinter sprinter;
+    INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
 
-        fprintf(stdout, "--- PC COUNTS %s:%d ---\n", script->filename, script->lineno);
-        js_Disassemble(cx, script, true, &sprinter);
-        fprintf(stdout, "%s\n", sprinter.base);
-        fprintf(stdout, "--- END PC COUNTS %s:%d ---\n", script->filename, script->lineno);
-    }
+    fprintf(stdout, "--- SCRIPT %s:%d ---\n", script->filename, script->lineno);
+    js_Disassemble(cx, script, true, &sprinter);
+    fprintf(stdout, "%s\n", sprinter.base);
+    fprintf(stdout, "--- END SCRIPT %s:%d ---\n", script->filename, script->lineno);
 #endif
 }
 
 JS_PUBLIC_API(void)
-JS_DumpAllProfiles(JSContext *cx)
+JS_DumpCompartmentBytecode(JSContext *cx)
 {
     for (JSScript *script = (JSScript *) JS_LIST_HEAD(&cx->compartment->scripts);
          script != (JSScript *) &cx->compartment->scripts;
          script = (JSScript *) JS_NEXT_LINK((JSCList *)script))
     {
-        JS_DumpProfile(cx, script);
+        JS_DumpBytecode(cx, script);
     }
 }
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -492,55 +492,102 @@ JS_GetGlobalDebugHooks(JSRuntime *rt);
 
 extern JS_PUBLIC_API(JSDebugHooks *)
 JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks);
 
 /* Disable debug hooks for this context. */
 extern JS_PUBLIC_API(JSDebugHooks *)
 JS_ClearContextDebugHooks(JSContext *cx);
 
+/**
+ * Start any profilers that are available and have been configured on for this
+ * platform. This is NOT thread safe.
+ *
+ * The profileName is used by some profilers to describe the current profiling
+ * run. It may be used for part of the filename of the output, but the
+ * specifics depend on the profiler. Many profilers will ignore it. Passing in
+ * NULL is legal; some profilers may use it to output to stdout or similar.
+ *
+ * Returns true if no profilers fail to start.
+ */
 extern JS_PUBLIC_API(JSBool)
-JS_StartProfiling();
+JS_StartProfiling(const char *profileName);
+
+/**
+ * Stop any profilers that were previously started with JS_StartProfiling.
+ * Returns true if no profilers fail to stop.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_StopProfiling(const char *profileName);
 
-extern JS_PUBLIC_API(void)
-JS_StopProfiling();
+/**
+ * Write the current profile data to the given file, if applicable to whatever
+ * profiler is being used.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_DumpProfile(const char *outfile, const char *profileName);
 
+/**
+ * Pause currently active profilers (only supported by some profilers). Returns
+ * whether any profilers failed to pause. (Profilers that do not support
+ * pause/resume do not count.)
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_PauseProfilers(const char *profileName);
+
+/**
+ * Resume suspended profilers
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ResumeProfilers(const char *profileName);
+
+/**
+ * Add various profiling-related functions as properties of the given object.
+ */
 extern JS_PUBLIC_API(JSBool)
 JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj);
 
 /* Defined in vm/Debugger.cpp. */
 extern JS_PUBLIC_API(JSBool)
 JS_DefineDebuggerObject(JSContext *cx, JSObject *obj);
 
+/**
+ * The profiling API calls are not able to report errors, so they use a
+ * thread-unsafe global memory buffer to hold the last error encountered. This
+ * should only be called after something returns false.
+ */
+JS_PUBLIC_API(const char *)
+JS_UnsafeGetLastProfilingError();
+
 #ifdef MOZ_CALLGRIND
 
 extern JS_FRIEND_API(JSBool)
-js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp);
+js_StopCallgrind();
 
 extern JS_FRIEND_API(JSBool)
-js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp);
+js_StartCallgrind();
 
 extern JS_FRIEND_API(JSBool)
-js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp);
+js_DumpCallgrind(const char *outfile);
 
 #endif /* MOZ_CALLGRIND */
 
 #ifdef MOZ_VTUNE
 
-extern JS_FRIEND_API(JSBool)
-js_StartVtune(JSContext *cx, uintN argc, jsval *vp);
+extern JS_FRIEND_API(bool)
+js_StartVtune(const char *profileName);
 
-extern JS_FRIEND_API(JSBool)
-js_StopVtune(JSContext *cx, uintN argc, jsval *vp);
+extern JS_FRIEND_API(bool)
+js_StopVtune();
 
-extern JS_FRIEND_API(JSBool)
-js_PauseVtune(JSContext *cx, uintN argc, jsval *vp);
+extern JS_FRIEND_API(bool)
+js_PauseVtune();
 
-extern JS_FRIEND_API(JSBool)
-js_ResumeVtune(JSContext *cx, uintN argc, jsval *vp);
+extern JS_FRIEND_API(bool)
+js_ResumeVtune();
 
 #endif /* MOZ_VTUNE */
 
 #ifdef MOZ_TRACEVIS
 extern JS_FRIEND_API(JSBool)
 js_InitEthogram(JSContext *cx, uintN argc, jsval *vp);
 extern JS_FRIEND_API(JSBool)
 js_ShutdownEthogram(JSContext *cx, uintN argc, jsval *vp);
@@ -564,16 +611,16 @@ typedef void (*JSFunctionCallback)(const
 extern JS_PUBLIC_API(void)
 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb);
 
 extern JS_PUBLIC_API(JSFunctionCallback)
 JS_GetFunctionCallback(JSContext *cx);
 #endif /* MOZ_TRACE_JSCALLS */
 
 extern JS_PUBLIC_API(void)
-JS_DumpProfile(JSContext *cx, JSScript *script);
+JS_DumpBytecode(JSContext *cx, JSScript *script);
 
 extern JS_PUBLIC_API(void)
-JS_DumpAllProfiles(JSContext *cx);
+JS_DumpCompartmentBytecode(JSContext *cx);
 
 JS_END_EXTERN_C
 
 #endif /* jsdbgapi_h___ */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2197,17 +2197,16 @@ SweepCompartments(JSContext *cx, JSGCInv
 
     while (read < end) {
         JSCompartment *compartment = *read++;
 
         if (!compartment->hold &&
             (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT))
         {
             compartment->freeLists.checkEmpty();
-            Probes::GCEndSweepPhase(compartment);
             if (callback)
                 JS_ALWAYS_TRUE(callback(cx, compartment, JSCOMPARTMENT_DESTROY));
             if (compartment->principals)
                 JSPRINCIPALS_DROP(cx, compartment->principals);
             cx->delete_(compartment);
             continue;
         }
         *write++ = compartment;
@@ -2333,23 +2332,25 @@ MarkAndSweep(JSContext *cx, JSCompartmen
     /*
      * We finalize objects before other GC things to ensure that object's finalizer
      * can access them even if they will be freed. Sweep the runtime's property trees
      * after finalizing objects, in case any had watchpoints referencing tree nodes.
      * Do this before sweeping compartments, so that we sweep all shapes in
      * unreachable compartments.
      */
     if (comp) {
+        Probes::GCStartSweepPhase(comp);
         comp->sweep(cx, 0);
         comp->finalizeObjectArenaLists(cx);
         GCTIMESTAMP(sweepObjectEnd);
         comp->finalizeStringArenaLists(cx);
         GCTIMESTAMP(sweepStringEnd);
         comp->finalizeShapeArenaLists(cx);
         GCTIMESTAMP(sweepShapeEnd);
+        Probes::GCEndSweepPhase(comp);
     } else {
         /*
          * Some sweeping is not compartment-specific. Start a NULL-compartment
          * phase to demarcate all of that. (The compartment sweeps will nest
          * within.)
          */
         Probes::GCStartSweepPhase(NULL);
 
--- a/js/src/jsprobes.cpp
+++ b/js/src/jsprobes.cpp
@@ -48,154 +48,98 @@
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsinterp.h"
 #include "jsobj.h"
 #include "jsscript.h"
 #include "jsstaticcheck.h"
 #include "jsstr.h"
 
-#ifdef __APPLE__
-#include "sharkctl.h"
-#endif
-
 #include "jsprobes.h"
 #include <sys/types.h>
 
 #define TYPEOF(cx,v)    (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
 
 using namespace js;
 
 const char Probes::nullName[] = "(null)";
 const char Probes::anonymousName[] = "(anonymous)";
 
 bool Probes::ProfilingActive = true;
 
-bool
-Probes::controlProfilers(JSContext *cx, bool toState)
+#ifdef INCLUDE_MOZILLA_DTRACE
+static const char *
+ScriptFilename(const JSScript *script)
 {
-    JSBool ok = JS_TRUE;
-#if defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE)
-    jsval dummy;
-#endif
+    if (!script)
+        return Probes::nullName;
+    if (!script->filename)
+        return Probes::anonymousName;
+    return script->filename;
+}
+
+static const char *
+FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString* bytes)
+{
+    if (!fun)
+        return Probes::nullName;
+    JSAtom *atom = const_cast<JSAtom*>(fun->atom);
+    if (!atom)
+        return Probes::anonymousName;
+    return bytes->encode(cx, atom) ? bytes->ptr() : Probes::nullName;
+}
 
-    if (! ProfilingActive && toState) {
-#if defined(MOZ_SHARK) && defined(__APPLE__)
-        if (!Shark::Start())
-            ok = JS_FALSE;
-#endif
-#ifdef MOZ_CALLGRIND
-        if (! js_StartCallgrind(cx, 0, &dummy))
-            ok = JS_FALSE;
-#endif
-#ifdef MOZ_VTUNE
-        if (! js_ResumeVtune(cx, 0, &dummy))
-            ok = JS_FALSE;
-#endif
-    } else if (ProfilingActive && ! toState) {
-#if defined(MOZ_SHARK) && defined(__APPLE__)
-        Shark::Stop();
-#endif
-#ifdef MOZ_CALLGRIND
-        if (! js_StopCallgrind(cx, 0, &dummy))
-            ok = JS_FALSE;
-#endif
-#ifdef MOZ_VTUNE
-        if (! js_PauseVtune(cx, 0, &dummy))
-            ok = JS_FALSE;
-#endif
-    }
+static const char *
+FunctionClassname(const JSFunction *fun)
+{
+    if (!fun || FUN_INTERPRETED(fun))
+        return Probes::nullName;
+    if (!(fun->flags & JSFUN_TRCINFO) && FUN_CLASP(fun))
+        return (char *)FUN_CLASP(fun)->name;
+    return Probes::nullName;
+}
 
-    ProfilingActive = toState;
-
-    return ok;
+/*
+ * These functions call the DTrace macros for the JavaScript USDT probes.
+ * Originally this code was inlined in the JavaScript code; however since
+ * a number of operations are called, these have been placed into functions
+ * to reduce any negative compiler optimization effect that the addition of
+ * a number of usually unused lines of code would cause.
+ */
+void
+Probes::DTraceEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
+{
+    JSAutoByteString funNameBytes;
+    JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), FunctionClassname(fun),
+                              FunctionName(cx, fun, &funNameBytes));
 }
 
 void
-Probes::current_location(JSContext *cx, int* lineno, char const **filename)
+Probes::DTraceExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
+{
+    JSAutoByteString funNameBytes;
+    JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), FunctionClassname(fun),
+                               FunctionName(cx, fun, &funNameBytes));
+}
+#endif
+
+#ifdef MOZ_ETW
+static void
+current_location(JSContext *cx, int* lineno, char const **filename)
 {
     JSScript *script = js_GetCurrentScript(cx);
     if (! script) {
         *lineno = -1;
         *filename = "(uninitialized)";
         return;
     }
     *lineno = js_PCToLineNumber(cx, script, js_GetCurrentBytecodePC(cx));
     *filename = ScriptFilename(script);
 }
 
-const char *
-Probes::FunctionClassname(const JSFunction *fun)
-{
-    return (fun && !FUN_INTERPRETED(fun) && !(fun->flags & JSFUN_TRCINFO) && FUN_CLASP(fun))
-           ? (char *)FUN_CLASP(fun)->name
-           : nullName;
-}
-
-const char *
-Probes::ScriptFilename(JSScript *script)
-{
-    return (script && script->filename) ? (char *)script->filename : nullName;
-}
-
-int
-Probes::FunctionLineNumber(JSContext *cx, const JSFunction *fun)
-{
-    if (fun && FUN_INTERPRETED(fun))
-        return (int) JS_GetScriptBaseLineNumber(cx, FUN_SCRIPT(fun));
-
-    return 0;
-}
-
-#ifdef INCLUDE_MOZILLA_DTRACE
-/*
- * These functions call the DTrace macros for the JavaScript USDT probes.
- * Originally this code was inlined in the JavaScript code; however since
- * a number of operations are called, these have been placed into functions
- * to reduce any negative compiler optimization effect that the addition of
- * a number of usually unused lines of code would cause.
- */
-void
-Probes::enterJSFunImpl(JSContext *cx, JSFunction *fun, JSScript *script)
-{
-    JSAutoByteString funNameBytes;
-    JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), FunctionClassname(fun),
-                              FunctionName(cx, fun, &funNameBytes));
-}
-
-void
-Probes::handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script)
-{
-    JSAutoByteString funNameBytes;
-    JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), FunctionClassname(fun),
-                               FunctionName(cx, fun, &funNameBytes));
-}
-
-#endif
-
-bool
-Probes::startProfiling()
-{
-#if defined(MOZ_SHARK) && defined(__APPLE__)
-    if (Shark::Start())
-        return true;
-#endif
-    return false;
-}
-
-void
-Probes::stopProfiling()
-{
-#if defined(MOZ_SHARK) && defined(__APPLE__)
-    Shark::Stop();
-#endif
-}
-
-
-#ifdef MOZ_ETW
 /*
  * ETW (Event Tracing for Windows)
  *
  * These are here rather than in the .h file to avoid having to include
  * windows.h in a header.
  */
 bool
 Probes::ETWCallTrackingActive(JSContext *cx)
--- a/js/src/jsprobes.h
+++ b/js/src/jsprobes.h
@@ -9,20 +9,24 @@
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
- * Copyright (C) 2007  Sun Microsystems, Inc. All Rights Reserved.
+ * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
+ * June 12, 2009.
+ *
+ * The Initial Developer of the Original Code is
+ *   the Mozilla Corporation.
  *
  * Contributor(s):
- *      Brendan Eich <brendan@mozilla.org>
+ *      Steve Fink <sfink@mozilla.org>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -39,178 +43,214 @@
 #ifdef INCLUDE_MOZILLA_DTRACE
 #include "javascript-trace.h"
 #endif
 #include "jspubtd.h"
 #include "jsprvtd.h"
 
 namespace js {
 
-class Probes {
-    static bool ProfilingActive;
-    static bool controlProfilers(JSContext *cx, bool toState);
-
-    static const char nullName[];
-    static const char anonymousName[];
-
-    static const char *FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString* bytes)
-    {
-        if (!fun)
-            return nullName;
-        JSAtom *atom = const_cast<JSAtom*>(fun->atom);
-        if (!atom)
-            return anonymousName;
-        return bytes->encode(cx, atom) ? bytes->ptr() : nullName;
-    }
+namespace Probes {
 
-    static const char *ScriptFilename(const JSScript *script) {
-        if (! script)
-            return "(null)";
-        if (! script->filename)
-            return "(anonymous)";
-        return script->filename;
-    }
+/*
+ * Static probes
+ *
+ * The probe points defined in this file are scattered around the SpiderMonkey
+ * source tree. The presence of Probes::someEvent() means that someEvent is
+ * about to happen or has happened. To the extent possible, probes should be
+ * inserted in all paths associated with a given event, regardless of the
+ * active runmode (interpreter/traceJIT/methodJIT/ionJIT).
+ *
+ * When a probe fires, it is handled by any probe handling backends that have
+ * been compiled in. By default, most probes do nothing or at least do nothing
+ * expensive, so the presence of the probe should have negligible effect on
+ * running time. (Probes in slow paths may do something by default, as long as
+ * there is no noticeable slowdown.)
+ *
+ * For some probes, the mere existence of the probe is too expensive even if it
+ * does nothing when called. For example, just having consistent information
+ * available for a function call entry/exit probe causes the JITs to
+ * de-optimize function calls. In those cases, the JITs may query at compile
+ * time whether a probe is desired, and omit the probe invocation if not. If a
+ * probe is runtime-disabled at compilation time, it is not guaranteed to fire
+ * within a compiled function if it is later enabled.
+ *
+ * Not all backends handle all of the probes listed here.
+ */
 
-    static const char *ObjectClassname(JSObject *obj) {
-        if (! obj)
-            return "(null object)";
-        Class *clasp = obj->getClass();
-        if (! clasp)
-            return "(null)";
-        const char *class_name = clasp->name;
-        if (! class_name)
-            return "(null class name)";
-        return class_name;
-    }
+/*
+ * Internal use only: remember whether "profiling", whatever that means, is
+ * currently active. Used for state management.
+ */
+extern bool ProfilingActive;
+
+extern const char nullName[];
+extern const char anonymousName[];
 
-    static void current_location(JSContext *cx, int* lineno, char const **filename);
+/* JSRuntime created, with currently valid fields */
+bool createRuntime(JSRuntime *rt);
+
+/* JSRuntime about to be destroyed */
+bool destroyRuntime(JSRuntime *rt);
+
+/* Total JS engine shutdown */
+bool shutdown();
 
-    static const char *FunctionClassname(const JSFunction *fun);
-    static const char *ScriptFilename(JSScript *script);
-    static int FunctionLineNumber(JSContext *cx, const JSFunction *fun);
+/*
+ * Test whether we are tracking JS function call enter/exit. The JITs use this
+ * to decide whether they can optimize in a way that would prevent probes from
+ * firing.
+ */
+bool callTrackingActive(JSContext *);
+
+/* Entering a JS function */
+bool enterJSFun(JSContext *, JSFunction *, JSScript *, int counter = 1);
 
-    static void enterJSFunImpl(JSContext *cx, JSFunction *fun, JSScript *script);
-    static void handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script);
-    static void finalizeObjectImpl(JSObject *obj);
-  public:
-    static bool createRuntime(JSRuntime *rt);
-    static bool destroyRuntime(JSRuntime *rt);
-    static bool shutdown();
+/* About to leave a JS function */
+bool exitJSFun(JSContext *, JSFunction *, JSScript *, int counter = 0);
+
+/* Executing a script */
+bool startExecution(JSContext *cx, JSScript *script);
+
+/* Script has completed execution */
+bool stopExecution(JSContext *cx, JSScript *script);
+
+/* Heap has been resized */
+bool resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
 
-    /*
-     * Pause/resume whatever profiling mechanism is currently compiled
-     * in, if applicable. This will not affect things like dtrace.
-     *
-     * Do not mix calls to these APIs with calls to the individual
-     * profilers' pase/resume functions, because only overall state is
-     * tracked, not the state of each profiler.
-     *
-     * Return the previous state.
-     */
-    static bool pauseProfilers(JSContext *cx) {
-        bool prevState = ProfilingActive;
-        controlProfilers(cx, false);
-        return prevState;
-    }
-    static bool resumeProfilers(JSContext *cx) {
-        bool prevState = ProfilingActive;
-        controlProfilers(cx, true);
-        return prevState;
-    }
+/*
+ * Object has been created. |obj| must exist (its class and size are read)
+ */
+bool createObject(JSContext *cx, JSObject *obj);
+
+/* Object has been resized */
+bool resizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
+
+/*
+ * Object is about to be finalized. |obj| must still exist (its class is
+ * read)
+ */
+bool finalizeObject(JSObject *obj);
 
-    static bool callTrackingActive(JSContext *);
+/*
+ * String has been created.
+ *
+ * |string|'s content is not (yet) valid. |length| is the length of the string
+ * and does not imply anything about the amount of storage consumed to store
+ * the string. (It may be a short string, an external string, or a rope, and
+ * the encoding is not taken into consideration.)
+ */
+bool createString(JSContext *cx, JSString *string, size_t length);
 
-    static bool enterJSFun(JSContext *, JSFunction *, JSScript *, int counter = 1);
-    static bool exitJSFun(JSContext *, JSFunction *, JSScript *, int counter = 0);
-
-    static bool startExecution(JSContext *cx, JSScript *script);
-    static bool stopExecution(JSContext *cx, JSScript *script);
+/*
+ * String is about to be finalized
+ *
+ * |string| must still have a valid length.
+ */
+bool finalizeString(JSString *string);
 
-    static bool resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
+/* Script is about to be compiled */
+bool compileScriptBegin(JSContext *cx, const char *filename, int lineno);
 
-    /* |obj| must exist (its class and size are computed) */
-    static bool createObject(JSContext *cx, JSObject *obj);
+/* Script has just finished compilation */
+bool compileScriptEnd(JSContext *cx, JSScript *script, const char *filename, int lineno);
 
-    static bool resizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
+/* About to make a call from JS into native code */
+bool calloutBegin(JSContext *cx, JSFunction *fun);
 
-    /* |obj| must still exist (its class is accessed) */
-    static bool finalizeObject(JSObject *obj);
+/* Native code called by JS has terminated */
+bool calloutEnd(JSContext *cx, JSFunction *fun);
+
+/* Unimplemented */
+bool acquireMemory(JSContext *cx, void *address, size_t nbytes);
+bool releaseMemory(JSContext *cx, void *address, size_t nbytes);
 
-    /*
-     * |string| does not need to contain any content yet; only its
-     * pointer value is used. |length| is the length of the string and
-     * does not imply anything about the amount of storage consumed to
-     * store the string. (It may be a short string, an external
-     * string, or a rope, and the encoding is not taken into
-     * consideration.)
-     */
-    static bool createString(JSContext *cx, JSString *string, size_t length);
+/*
+ * Garbage collection probes
+ *
+ * GC timing is tricky and at the time of this writing is changing frequently.
+ * GCStart(NULL)/GCEnd(NULL) are intended to bracket the entire garbage
+ * collection (either global or single-compartment), but a separate thread may
+ * continue doing work after GCEnd.
+ *
+ * Multiple compartments' GC will be interleaved during a global collection
+ * (eg, compartment 1 starts, compartment 2 starts, compartment 1 ends, ...)
+ */
+bool GCStart(JSCompartment *compartment);
+bool GCEnd(JSCompartment *compartment);
 
-    /*
-     * |string| must still have a valid length.
-     */
-    static bool finalizeString(JSString *string);
+bool GCStartMarkPhase(JSCompartment *compartment);
+bool GCEndMarkPhase(JSCompartment *compartment);
 
-    static bool compileScriptBegin(JSContext *cx, const char *filename, int lineno);
-    static bool compileScriptEnd(JSContext *cx, JSScript *script, const char *filename, int lineno);
+bool GCStartSweepPhase(JSCompartment *compartment);
+bool GCEndSweepPhase(JSCompartment *compartment);
 
-    static bool calloutBegin(JSContext *cx, JSFunction *fun);
-    static bool calloutEnd(JSContext *cx, JSFunction *fun);
-
-    static bool acquireMemory(JSContext *cx, void *address, size_t nbytes);
-    static bool releaseMemory(JSContext *cx, void *address, size_t nbytes);
-
-    static bool GCStart(JSCompartment *compartment);
-    static bool GCEnd(JSCompartment *compartment);
-    static bool GCStartMarkPhase(JSCompartment *compartment);
+/*
+ * Various APIs for inserting custom probe points. These might be used to mark
+ * when something starts and stops, or for various other purposes the user has
+ * in mind. These are useful to export to JS so that JS code can mark
+ * application-meaningful events and phases of execution.
+ *
+ * Not all backends support these.
+ */
+bool CustomMark(JSString *string);
+bool CustomMark(const char *string);
+bool CustomMark(int marker);
 
-    static bool GCEndMarkPhase(JSCompartment *compartment);
-    static bool GCStartSweepPhase(JSCompartment *compartment);
-    static bool GCEndSweepPhase(JSCompartment *compartment);
+/*
+ * Internal: DTrace-specific functions to be called during Probes::enterJSFun
+ * and Probes::exitJSFun. These will not be inlined, but the argument
+ * marshalling required for these probe points is expensive enough that it
+ * shouldn't really matter.
+ */
+void DTraceEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script);
+void DTraceExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script);
 
-    static bool CustomMark(JSString *string);
-    static bool CustomMark(const char *string);
-    static bool CustomMark(int marker);
-
-    static bool startProfiling();
-    static void stopProfiling();
-
+/*
+ * Internal: ETW-specific probe functions
+ */
 #ifdef MOZ_ETW
-    // ETW Handlers
-    static bool ETWCreateRuntime(JSRuntime *rt);
-    static bool ETWDestroyRuntime(JSRuntime *rt);
-    static bool ETWShutdown();
-    static bool ETWCallTrackingActive(JSContext *cx);
-    static bool ETWEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
-    static bool ETWExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
-    static bool ETWCreateObject(JSContext *cx, JSObject *obj);
-    static bool ETWFinalizeObject(JSObject *obj);
-    static bool ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
-    static bool ETWCreateString(JSContext *cx, JSString *string, size_t length);
-    static bool ETWFinalizeString(JSString *string);
-    static bool ETWCompileScriptBegin(const char *filename, int lineno);
-    static bool ETWCompileScriptEnd(const char *filename, int lineno);
-    static bool ETWCalloutBegin(JSContext *cx, JSFunction *fun);
-    static bool ETWCalloutEnd(JSContext *cx, JSFunction *fun);
-    static bool ETWAcquireMemory(JSContext *cx, void *address, size_t nbytes);
-    static bool ETWReleaseMemory(JSContext *cx, void *address, size_t nbytes);
-    static bool ETWGCStart(JSCompartment *compartment);
-    static bool ETWGCEnd(JSCompartment *compartment);
-    static bool ETWGCStartMarkPhase(JSCompartment *compartment);
-    static bool ETWGCEndMarkPhase(JSCompartment *compartment);
-    static bool ETWGCStartSweepPhase(JSCompartment *compartment);
-    static bool ETWGCEndSweepPhase(JSCompartment *compartment);
-    static bool ETWCustomMark(JSString *string);
-    static bool ETWCustomMark(const char *string);
-    static bool ETWCustomMark(int marker);
-    static bool ETWStartExecution(JSContext *cx, JSScript *script);
-    static bool ETWStopExecution(JSContext *cx, JSScript *script);
-    static bool ETWResizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
+// ETW Handlers
+bool ETWCreateRuntime(JSRuntime *rt);
+bool ETWDestroyRuntime(JSRuntime *rt);
+bool ETWShutdown();
+bool ETWCallTrackingActive(JSContext *cx);
+bool ETWEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
+bool ETWExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
+bool ETWCreateObject(JSContext *cx, JSObject *obj);
+bool ETWFinalizeObject(JSObject *obj);
+bool ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
+bool ETWCreateString(JSContext *cx, JSString *string, size_t length);
+bool ETWFinalizeString(JSString *string);
+bool ETWCompileScriptBegin(const char *filename, int lineno);
+bool ETWCompileScriptEnd(const char *filename, int lineno);
+bool ETWCalloutBegin(JSContext *cx, JSFunction *fun);
+bool ETWCalloutEnd(JSContext *cx, JSFunction *fun);
+bool ETWAcquireMemory(JSContext *cx, void *address, size_t nbytes);
+bool ETWReleaseMemory(JSContext *cx, void *address, size_t nbytes);
+bool ETWGCStart(JSCompartment *compartment);
+bool ETWGCEnd(JSCompartment *compartment);
+bool ETWGCStartMarkPhase(JSCompartment *compartment);
+bool ETWGCEndMarkPhase(JSCompartment *compartment);
+bool ETWGCStartSweepPhase(JSCompartment *compartment);
+bool ETWGCEndSweepPhase(JSCompartment *compartment);
+bool ETWCustomMark(JSString *string);
+bool ETWCustomMark(const char *string);
+bool ETWCustomMark(int marker);
+bool ETWStartExecution(JSContext *cx, JSScript *script);
+bool ETWStopExecution(JSContext *cx, JSScript *script);
+bool ETWResizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
 #endif
-};
+
+} /* namespace Probes */
+
+/*
+ * Probe handlers are implemented inline for minimal performance impact,
+ * especially important when no backends are enabled.
+ */
 
 inline bool
 Probes::createRuntime(JSRuntime *rt)
 {
     bool ok = true;
 #ifdef MOZ_ETW
     if (!ETWCreateRuntime(rt))
         ok = false;
@@ -253,40 +293,23 @@ Probes::callTrackingActive(JSContext *cx
 #endif
 #ifdef MOZ_ETW
     if (ProfilingActive && ETWCallTrackingActive(cx))
         return true;
 #endif
     return false;
 }
 
-extern inline JS_FRIEND_API(JSBool)
-js_PauseProfilers(JSContext *cx, uintN argc, jsval *vp)
-{
-    Probes::pauseProfilers(cx);
-    return JS_TRUE;
-}
-
-extern inline JS_FRIEND_API(JSBool)
-js_ResumeProfilers(JSContext *cx, uintN argc, jsval *vp)
-{
-    Probes::resumeProfilers(cx);
-    return JS_TRUE;
-}
-
-extern JS_FRIEND_API(JSBool)
-js_ResumeProfilers(JSContext *cx, uintN argc, jsval *vp);
-
 inline bool
 Probes::enterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
 {
     bool ok = true;
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
-        enterJSFunImpl(cx, fun, script);
+        DTraceEnterJSFun(cx, fun, script);
 #endif
 #ifdef MOZ_TRACE_JSCALLS
     cx->doFunctionCallback(fun, script, counter);
 #endif
 #ifdef MOZ_ETW
     if (ProfilingActive && !ETWEnterJSFun(cx, fun, script, counter))
         ok = false;
 #endif
@@ -296,17 +319,17 @@ Probes::enterJSFun(JSContext *cx, JSFunc
 
 inline bool
 Probes::exitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
 {
     bool ok = true;
 
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
-        handleFunctionReturn(cx, fun, script);
+        DTraceExitJSFun(cx, fun, script);
 #endif
 #ifdef MOZ_TRACE_JSCALLS
     if (counter > 0)
         counter = -counter;
     cx->doFunctionCallback(fun, script, counter);
 #endif
 #ifdef MOZ_ETW
     if (ProfilingActive && !ETWExitJSFun(cx, fun, script, counter))
@@ -324,16 +347,30 @@ Probes::resizeHeap(JSCompartment *compar
 #ifdef MOZ_ETW
     if (ProfilingActive && !ETWResizeHeap(compartment, oldSize, newSize))
         ok = false;
 #endif
 
     return ok;
 }
 
+#ifdef INCLUDE_MOZILLA_DTRACE
+static const char *ObjectClassname(JSObject *obj) {
+    if (! obj)
+        return "(null object)";
+    Class *clasp = obj->getClass();
+    if (! clasp)
+        return "(null)";
+    const char *class_name = clasp->name;
+    if (! class_name)
+        return "(null class name)";
+    return class_name;
+}
+#endif
+
 inline bool
 Probes::createObject(JSContext *cx, JSObject *obj)
 {
     bool ok = true;
 
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
         JAVASCRIPT_OBJECT_CREATE(ObjectClassname(obj), (uintptr_t)obj);
@@ -652,10 +689,15 @@ struct AutoFunctionCallProbe {
     }
 
     ~AutoFunctionCallProbe() {
         Probes::exitJSFun(cx, fun, script);
     }
 };
 
 } /* namespace js */
-    
+
+/*
+ * Internal functions for controlling various profilers. The profiler-specific
+ * implementations of these are mostly in jsdbgapi.cpp.
+ */
+
 #endif /* _JSPROBES_H */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3955,29 +3955,16 @@ static JSFunctionSpec shell_functions[] 
     JS_FN("clone",          Clone,          1,0),
     JS_FN("getpda",         GetPDA,         1,0),
     JS_FN("getslx",         GetSLX,         1,0),
     JS_FN("toint32",        ToInt32,        1,0),
     JS_FN("evalcx",         EvalInContext,  1,0),
     JS_FN("evalInFrame",    EvalInFrame,    2,0),
     JS_FN("shapeOf",        ShapeOf,        1,0),
     JS_FN("resolver",       Resolver,       1,0),
-    JS_FN("pauseProfilers", js_PauseProfilers, 0,0),
-    JS_FN("resumeProfilers", js_ResumeProfilers, 0,0),
-#ifdef MOZ_CALLGRIND
-    JS_FN("startCallgrind", js_StartCallgrind,  0,0),
-    JS_FN("stopCallgrind",  js_StopCallgrind,   0,0),
-    JS_FN("dumpCallgrind",  js_DumpCallgrind,   1,0),
-#endif
-#ifdef MOZ_VTUNE
-    JS_FN("startVtune",     js_StartVtune,    1,0),
-    JS_FN("stopVtune",      js_StopVtune,     0,0),
-    JS_FN("pauseVtune",     js_PauseVtune,    0,0),
-    JS_FN("resumeVtune",    js_ResumeVtune,   0,0),
-#endif
 #ifdef MOZ_TRACEVIS
     JS_FN("startTraceVis",  StartTraceVisNative, 1,0),
     JS_FN("stopTraceVis",   StopTraceVisNative,  0,0),
 #endif
 #ifdef DEBUG
     JS_FN("arrayInfo",      js_ArrayInfo,   1,0),
 #endif
 #ifdef JS_THREADSAFE
@@ -4094,29 +4081,16 @@ static const char *const shell_help_mess
 "  Evaluate s in optional sandbox object o\n"
 "  if (s == '' && !o) return new o with eager standard classes\n"
 "  if (s == 'lazy' && !o) return new o with lazy standard classes",
 "evalInFrame(n,str,save)  Evaluate 'str' in the nth up frame.\n"
 "                         If 'save' (default false), save the frame chain",
 "shapeOf(obj)             Get the shape of obj (an implementation detail)",
 "resolver(src[, proto])   Create object with resolve hook that copies properties\n"
 "                         from src. If proto is omitted, use Object.prototype.",
-"pauseProfilers()         Pause all profilers that can be paused",
-"resumeProfilers()        Resume profilers if they are paused",
-#ifdef MOZ_CALLGRIND
-"startCallgrind()         Start callgrind instrumentation",
-"stopCallgrind()          Stop callgrind instrumentation",
-"dumpCallgrind([name])    Dump callgrind counters",
-#endif
-#ifdef MOZ_VTUNE
-"startVtune([filename])   Start vtune instrumentation",
-"stopVtune()              Stop vtune instrumentation",
-"pauseVtune()             Pause vtune collection",
-"resumeVtune()            Resume vtune collection",
-#endif
 #ifdef MOZ_TRACEVIS
 "startTraceVis(filename)  Start TraceVis recording (stops any current recording)",
 "stopTraceVis()           Stop TraceVis recording",
 #endif
 #ifdef DEBUG
 "arrayInfo(a1, a2, ...)   Report statistics about arrays",
 #endif
 #ifdef JS_THREADSAFE
@@ -4148,53 +4122,86 @@ static const char *const shell_help_mess
 "  Enables or disables a particularly expensive assertion in stack-walking\n"
 "  code.  If your test isn't ridiculously thorough, such that performing this\n"
 "  assertion increases test duration by an order of magnitude, you shouldn't\n"
 "  use this.",
 "getMaxArgs()             Return the maximum number of supported args for a call.",
 
 /* Keep these last: see the static assertion below. */
 #ifdef MOZ_PROFILING
-"startProfiling()         Start a profiling session.\n"
+"startProfiling([profileName])\n"
+"                         Start a profiling session\n"
 "                         Profiler must be running with programatic sampling",
-"stopProfiling()          Stop a running profiling session\n"
+"stopProfiling([profileName])\n"
+"                         Stop a running profiling session",
+"pauseProfilers([profileName])\n"
+"                         Pause a running profiling session",
+"resumeProfilers([profileName])\n"
+"                         Resume a paused profiling session",
+"dumpProfile([outfile[, profileName]])\n"
+"                         Dump out current profile info (only valid for callgrind)",
+# ifdef MOZ_CALLGRIND
+"startCallgrind()         Start Callgrind instrumentation",
+"stopCallgrind()          Stop Callgrind instrumentation",
+"dumpCallgrind([outfile]) Dump current Callgrind counters to file or stdout",
+# endif
+# ifdef MOZ_VTUNE
+"startVtune()             Start Vtune instrumentation",
+"stopVtune()              Stop Vtune instrumentation",
+"pauseVtune()             Pause Vtune collection",
+"resumeVtune()            Resume Vtune collection",
+# endif
 #endif
 };
 
 #ifdef MOZ_PROFILING
-#define PROFILING_FUNCTION_COUNT 2
+# define PROFILING_FUNCTION_COUNT 5
+# ifdef MOZ_CALLGRIND
+#  define CALLGRIND_FUNCTION_COUNT 3
+# else
+#  define CALLGRIND_FUNCTION_COUNT 0
+# endif
+# ifdef MOZ_VTUNE
+#  define VTUNE_FUNCTION_COUNT 4
+# else
+#  define VTUNE_FUNCTION_COUNT 0
+# endif
+# define EXTERNAL_FUNCTION_COUNT (PROFILING_FUNCTION_COUNT + CALLGRIND_FUNCTION_COUNT + VTUNE_FUNCTION_COUNT)
 #else
-#define PROFILING_FUNCTION_COUNT 0
+# define EXTERNAL_FUNCTION_COUNT 0
 #endif
 
 /* Help messages must match shell functions. */
-JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) - PROFILING_FUNCTION_COUNT ==
+JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) - EXTERNAL_FUNCTION_COUNT ==
                  JS_ARRAY_LENGTH(shell_functions) - 1 /* JS_FS_END */);
 
 #ifdef DEBUG
 static void
 CheckHelpMessages()
 {
     const char *const *m;
     const char *lp;
 
     /* Messages begin with "function_name(" prefix and don't end with \n. */
-    for (m = shell_help_messages; m != JS_ARRAY_END(shell_help_messages) - PROFILING_FUNCTION_COUNT; ++m) {
+    for (m = shell_help_messages; m != JS_ARRAY_END(shell_help_messages) - EXTERNAL_FUNCTION_COUNT; ++m) {
         lp = strchr(*m, '(');
         JS_ASSERT(lp);
         JS_ASSERT(memcmp(shell_functions[m - shell_help_messages].name,
                          *m, lp - *m) == 0);
         JS_ASSERT((*m)[strlen(*m) - 1] != '\n');
     }
 }
 #else
 # define CheckHelpMessages() ((void) 0)
 #endif
 
 #undef PROFILING_FUNCTION_COUNT
+#undef CALLGRIND_FUNCTION_COUNT
+#undef VTUNE_FUNCTION_COUNT
+#undef EXTERNAL_FUNCTION_COUNT
 
 static JSBool
 Help(JSContext *cx, uintN argc, jsval *vp)
 {
     uintN i, j;
     int did_header, did_something;
     JSType type;
     JSFunction *fun;
@@ -5216,17 +5223,17 @@ Shell(JSContext *cx, OptionParser *op, c
         if (jsdbc)
             JSDB_TermDebugger(jsdc);
 #endif /* JSDEBUGGER_C_UI */
         JSD_DebuggerOff(jsdc);
     }
 #endif  /* JSDEBUGGER */
 
     if (enableDisassemblyDumps)
-        JS_DumpAllProfiles(cx);
+        JS_DumpCompartmentBytecode(cx);
  
     return result;
 }
 
 static void
 MaybeOverrideOutFileFromEnv(const char* const envVar,
                             FILE* defaultOut,
                             FILE** outFile)
--- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp
@@ -286,27 +286,16 @@ File(JSContext *cx, uintN argc, jsval *v
 }
 
 static JSFunctionSpec gGlobalFun[] = {
     {"dump",    Dump,   1,0},
     {"debug",   Debug,  1,0},
     {"atob",    Atob,   1,0},
     {"btoa",    Btoa,   1,0},
     {"File",    File,   1,JSFUN_CONSTRUCTOR},
-#ifdef MOZ_CALLGRIND
-    {"startCallgrind",  js_StartCallgrind, 0,0},
-    {"stopCallgrind",   js_StopCallgrind,  0,0},
-    {"dumpCallgrind",   js_DumpCallgrind,  1,0},
-#endif
-#ifdef MOZ_VTUNE
-    {"startVtune",      js_StartVtune,     1,0},
-    {"stopVtune",       js_StopVtune,      0,0},
-    {"pauseVtune",      js_PauseVtune,     0,0},
-    {"resumeVtune",     js_ResumeVtune,    0,0},
-#endif
 #ifdef MOZ_TRACEVIS
     {"initEthogram",     js_InitEthogram,      0,0},
     {"shutdownEthogram", js_ShutdownEthogram,  0,0},
 #endif
     {nsnull,nsnull,0,0}
 };
 
 class JSCLContextHelper
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -842,21 +842,16 @@ static JSFunctionSpec glob_functions[] =
     {"clear",           Clear,          1,0},
     {"options",         Options,        0,0},
     JS_FN("parent",     Parent,         1,0),
 #ifdef DEBUG
     {"dumpHeap",        DumpHeap,       5,0},
 #endif
     {"sendCommand",     SendCommand,    1,0},
     {"getChildGlobalObject", GetChildGlobalObject, 0,0},
-#ifdef MOZ_CALLGRIND
-    {"startCallgrind",  js_StartCallgrind,  0,0},
-    {"stopCallgrind",   js_StopCallgrind,   0,0},
-    {"dumpCallgrind",   js_DumpCallgrind,   1,0},
-#endif
     {nsnull,nsnull,0,0}
 };
 
 JSClass global_class = {
     "global", 0,
     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   nsnull
 };
--- a/xpcom/tests/TestHarness.h
+++ b/xpcom/tests/TestHarness.h
@@ -51,16 +51,17 @@
 #include "nsStringGlue.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsIDirectoryService.h"
 #include "nsIFile.h"
 #include "nsIProperties.h"
 #include "nsXULAppAPI.h"
+#include "jsdbgapi.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 
 static PRUint32 gFailCount = 0;
 
 /**
  * Prints the given failure message and arguments using printf, prepending
@@ -90,27 +91,16 @@ void passed(const char* test)
 {
   printf("TEST-PASS | %s\n", test);
 }
 
 //-----------------------------------------------------------------------------
 // Code profiling
 //
 static const char* gCurrentProfile;
-static PRBool gProfilerTriedInit = PR_FALSE;
-static PRBool gProfilerInited = PR_FALSE;
-
-// Platform profilers must implement these functions.
-// Init and deinit are guaranteed to only be called once, and
-// StartProfile/StopProfile may assume that they are only called
-// when the profiler has successfully been initialized.
-static PRBool _PlatformInitProfiler();
-static PRBool _PlatformStartProfile(const char* profileName);
-static PRBool _PlatformStopProfile(const char* profileName);
-static PRBool _PlatformDeinitProfiler();
 
 /**
  * If the build has been configured properly, start the best code profiler
  * available on this platform.
  *
  * This is NOT thread safe.
  *
  * @precondition Profiling is not started
@@ -119,117 +109,45 @@ static PRBool _PlatformDeinitProfiler();
  *                    to this name, but check your platform's profiler
  *                    documentation for what this means.
  * @return PR_TRUE if profiling was available and successfully started.
  * @see StopProfiling
  */
 inline PRBool
 StartProfiling(const char* profileName)
 {
-    if (!gProfilerTriedInit) {
-        gProfilerTriedInit = PR_TRUE;
-        gProfilerInited = _PlatformInitProfiler();
-    }
-    if (!gProfilerInited)
-        return PR_FALSE;
-
     NS_ASSERTION(profileName, "need a name for this profile");
     NS_PRECONDITION(!gCurrentProfile, "started a new profile before stopping another");
 
-    PRBool rv = _PlatformStartProfile(profileName);
+    JSBool ok = JS_StartProfiling(profileName);
     gCurrentProfile = profileName;
-    return rv;
+    return ok ? PR_TRUE : PR_FALSE;
 }
 
 /**
  * Stop the platform's profiler.  For what this means, what happens after
  * stopping, and how the profile data can be accessed, check the 
  * documentation of your platform's profiler.
  *
  * This is NOT thread safe.
  *
  * @precondition Profiling was started
  * @return PR_TRUE if profiling was successfully stopped.
  * @see StartProfiling
  */
 inline PRBool
 StopProfiling()
 {
-    NS_ASSERTION(gProfilerTriedInit, "tried to stop profile before starting one");
-    if (!gProfilerInited)
-        return PR_FALSE;
-
     NS_PRECONDITION(gCurrentProfile, "tried to stop profile before starting one");
 
     const char* profileName = gCurrentProfile;
     gCurrentProfile = 0;
-    return _PlatformStopProfile(profileName);
-}
-
-//--------------------------------------------------
-// Shark impl
-#if defined(MOZ_SHARK)
-#include "jsdbgapi.h"
-
-static PRBool
-_PlatformInitProfiler()
-{
-    return PR_TRUE;
-}
-
-static PRBool
-_PlatformStartProfile(const char* profileName)
-{
-    return JS_StartProfiling() ? PR_TRUE : PR_FALSE;
-}
-
-static PRBool
-_PlatformStopProfile(const char* profileName)
-{
-    JS_StopProfiling();
-    return PR_TRUE;
-}
-
-static PRBool
-_PlatformDeinitProfiler()
-{
-    return PR_TRUE;
+    return JS_StopProfiling(profileName) ? PR_TRUE : PR_FALSE;
 }
 
-//--------------------------------------------------
-// Default, no-profiler impl
-#else 
-
-static PRBool
-_PlatformInitProfiler()
-{
-    NS_WARNING("Profiling is not available/configured for your platform.");
-    return PR_FALSE;
-}
-static PRBool
-_PlatformStartProfile(const char* profileName)
-{
-    NS_WARNING("Profiling is not available/configured for your platform.");
-    return PR_FALSE;
-}
-static PRBool
-_PlatformStopProfile(const char* profileName)
-{
-    NS_WARNING("Profiling is not available/configured for your platform.");
-    return PR_FALSE;
-}
-static PRBool
-_PlatformDeinitProfiler()
-{
-    NS_WARNING("Profiling is not available/configured for your platform.");
-    return PR_FALSE;
-}
-
-#endif
-
 //-----------------------------------------------------------------------------
 
 class ScopedLogging
 {
 public:
     ScopedLogging()
     {
         NS_LogInit();
@@ -259,20 +177,16 @@ class ScopedXPCOM : public nsIDirectoryS
         fail("NS_InitXPCOM2 returned failure code 0x%x", rv);
         mServMgr = NULL;
         return;
       }
     }
 
     ~ScopedXPCOM()
     {
-      if (gProfilerInited)
-        if (!_PlatformDeinitProfiler())
-          NS_WARNING("Problem shutting down profiler");
-
       // If we created a profile directory, we need to remove it.
       if (mProfD) {
         if (NS_FAILED(mProfD->Remove(PR_TRUE)))
           NS_WARNING("Problem removing profile direrctory");
 
         mProfD = nsnull;
       }