Back out c8f38fb18c6a (bug 673631) for breaking the Shark shell build
authorPhil Ringnalda <philringnalda@gmail.com>
Fri, 12 Aug 2011 19:24:22 -0700
changeset 75142 d7ccb99a2f2d04e406e9f91ff0ecd7dd811a5ed2
parent 75141 aea57f085401d68b3c6e9af301878021f95efabd
child 75143 19ab9ba1c62369998649c5c0192aeafc0b74a230
push idunknown
push userunknown
push dateunknown
bugs673631
milestone8.0a1
backs outc8f38fb18c6a388a6ef4723fabcfd099ac51a78f
Back out c8f38fb18c6a (bug 673631) for breaking the Shark shell build
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,16 +2958,35 @@ 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
 
@@ -2993,16 +3012,26 @@ 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,16 +554,21 @@ 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,17 +38,16 @@
  * 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"
@@ -1501,364 +1500,66 @@ 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()
+JS_PUBLIC_API(JSBool)
+JS_StartProfiling()
 {
-    return gLastError;
-}
-
-JS_PUBLIC_API(JSBool)
-JS_StartProfiling(const char *profileName)
-{
-    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;
+    return Probes::startProfiling();
 }
 
-/*
- * Start or stop whatever platform- and configuration-specific profiling
- * backends are available.
- */
-static JSBool
-ControlProfilers(bool toState)
+JS_PUBLIC_API(void)
+JS_StopProfiling()
 {
-    JSBool ok = JS_TRUE;
-
-    if (! Probes::ProfilingActive && toState) {
-#if defined(MOZ_SHARK) && defined(__APPLE__)
-        if (!Shark::Start()) {
-            UnsafeError("Failed to start Shark for %s", profileName);
-            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;
+    Probes::stopProfiling();
 }
 
 #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)
 {
-    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;
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling()));
+    return true;
 }
 
 static JSBool
 StopProfiling(JSContext *cx, uintN argc, jsval *vp)
 {
-    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));
+    JS_StopProfiling();
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     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,      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),
+    JS_FN("startProfiling",  StartProfiling,      0,0),
+    JS_FN("stopProfiling",   StopProfiling,       0,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)
 {
@@ -1870,40 +1571,50 @@ JS_DefineProfilingFunctions(JSContext *c
 #endif
 }
 
 #ifdef MOZ_CALLGRIND
 
 #include <valgrind/callgrind.h>
 
 JS_FRIEND_API(JSBool)
-js_StartCallgrind()
+js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp)
 {
     CALLGRIND_START_INSTRUMENTATION;
     CALLGRIND_ZERO_STATS;
-    return true;
+    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;
 }
 
 JS_FRIEND_API(JSBool)
-js_StopCallgrind()
+js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
 {
-    CALLGRIND_STOP_INSTRUMENTATION;
-    return true;
-}
+    JSString *str;
 
-JS_FRIEND_API(JSBool)
-js_DumpCallgrind(const char *outfile)
-{
-    if (outfile) {
-        CALLGRIND_DUMP_STATS_AT(outfile);
-    } else {
-        CALLGRIND_DUMP_STATS;
+    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;
+        }
     }
+    CALLGRIND_DUMP_STATS;
 
-    return true;
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
 }
 
 #endif /* MOZ_CALLGRIND */
 
 #ifdef MOZ_VTUNE
 #include <VTuneApi.h>
 
 static const char *vtuneErrorMessages[] = {
@@ -1928,18 +1639,18 @@ static const char *vtuneErrorMessages[] 
   "invalid 'event size' field",
   "sampling file already bound",
   "invalid event path",
   "invalid license",
   "invalid 'global options' field",
 
 };
 
-bool
-js_StartVtune(const char *profileName)
+JS_FRIEND_API(JSBool)
+js_StartVtune(JSContext *cx, uintN argc, jsval *vp)
 {
     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";
@@ -1956,64 +1667,72 @@ js_StartVtune(const char *profileName)
         0.1,  /* Sampling interval in ms */
         1,    /* 1 for event-based sampling, 0 for time-based */
 
         n_events,
         events,
         default_filename,
     };
 
-    if (profileName) {
-        char filename[strlen(profileName) + strlen("-vtune.tb5") + 1];
-        snprintf(filename, sizeof(filename), "%s-vtune.tb5", profileName);
-        params.tb5Filename = 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());
     }
 
     status = VTStartSampling(&params);
 
     if (params.tb5Filename != default_filename)
-        Foreground::free_(params.tb5Filename);
+        cx->free_(params.tb5Filename);
 
     if (status != 0) {
         if (status == VTAPI_MULTIPLE_RUNS)
             VTStopSampling(0);
         if (status < sizeof(vtuneErrorMessages))
-            UnsafeError("Vtune setup error: %s", vtuneErrorMessages[status]);
+            JS_ReportError(cx, "Vtune setup error: %s",
+                           vtuneErrorMessages[status]);
         else
-            UnsafeError("Vtune setup error: %d", status);
+            JS_ReportError(cx, "Vtune setup error: %d",
+                           status);
         return false;
     }
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
-bool
-js_StopVtune()
+JS_FRIEND_API(JSBool)
+js_StopVtune(JSContext *cx, uintN argc, jsval *vp)
 {
     U32 status = VTStopSampling(1);
     if (status) {
         if (status < sizeof(vtuneErrorMessages))
-            UnsafeError("Vtune shutdown error: %s", vtuneErrorMessages[status]);
+            JS_ReportError(cx, "Vtune shutdown error: %s",
+                           vtuneErrorMessages[status]);
         else
-            UnsafeError("Vtune shutdown error: %d", status);
+            JS_ReportError(cx, "Vtune shutdown error: %d",
+                           status);
         return false;
     }
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
-bool
-js_PauseVtune()
+JS_FRIEND_API(JSBool)
+js_PauseVtune(JSContext *cx, uintN argc, jsval *vp)
 {
     VTPause();
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
-bool
-js_ResumeVtune()
+JS_FRIEND_API(JSBool)
+js_ResumeVtune(JSContext *cx, uintN argc, jsval *vp)
 {
     VTResume();
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
 #endif /* MOZ_VTUNE */
 
 #ifdef MOZ_TRACEVIS
 /*
  * Ethogram - Javascript wrapper for TraceVis state
@@ -2474,34 +2193,37 @@ JS_PUBLIC_API(JSFunctionCallback)
 JS_GetFunctionCallback(JSContext *cx)
 {
     return cx->functionCallback;
 }
 
 #endif /* MOZ_TRACE_JSCALLS */
 
 JS_PUBLIC_API(void)
-JS_DumpBytecode(JSContext *cx, JSScript *script)
+JS_DumpProfile(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(!cx->runtime->gcRunning);
 
 #if defined(DEBUG)
-    AutoArenaAllocator mark(&cx->tempPool);
-    Sprinter sprinter;
-    INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
+    if (script->pcCounters) {
+        // Display hit counts for every JS code line
+        AutoArenaAllocator mark(&cx->tempPool);
+        Sprinter sprinter;
+        INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
 
-    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);
+        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);
+    }
 #endif
 }
 
 JS_PUBLIC_API(void)
-JS_DumpCompartmentBytecode(JSContext *cx)
+JS_DumpAllProfiles(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_DumpBytecode(cx, script);
+        JS_DumpProfile(cx, script);
     }
 }
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -495,98 +495,51 @@ 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(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);
+JS_StartProfiling();
 
-/**
- * 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);
+extern JS_PUBLIC_API(void)
+JS_StopProfiling();
 
-/**
- * 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);
 
-/**
- * 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();
+js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp);
 
 extern JS_FRIEND_API(JSBool)
-js_StartCallgrind();
+js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp);
 
 extern JS_FRIEND_API(JSBool)
-js_DumpCallgrind(const char *outfile);
+js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp);
 
 #endif /* MOZ_CALLGRIND */
 
 #ifdef MOZ_VTUNE
 
-extern JS_FRIEND_API(bool)
-js_StartVtune(const char *profileName);
+extern JS_FRIEND_API(JSBool)
+js_StartVtune(JSContext *cx, uintN argc, jsval *vp);
 
-extern JS_FRIEND_API(bool)
-js_StopVtune();
+extern JS_FRIEND_API(JSBool)
+js_StopVtune(JSContext *cx, uintN argc, jsval *vp);
 
-extern JS_FRIEND_API(bool)
-js_PauseVtune();
+extern JS_FRIEND_API(JSBool)
+js_PauseVtune(JSContext *cx, uintN argc, jsval *vp);
 
-extern JS_FRIEND_API(bool)
-js_ResumeVtune();
+extern JS_FRIEND_API(JSBool)
+js_ResumeVtune(JSContext *cx, uintN argc, jsval *vp);
 
 #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);
@@ -610,16 +563,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_DumpBytecode(JSContext *cx, JSScript *script);
+JS_DumpProfile(JSContext *cx, JSScript *script);
 
 extern JS_PUBLIC_API(void)
-JS_DumpCompartmentBytecode(JSContext *cx);
+JS_DumpAllProfiles(JSContext *cx);
 
 JS_END_EXTERN_C
 
 #endif /* jsdbgapi_h___ */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2197,16 +2197,17 @@ 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;
@@ -2331,25 +2332,23 @@ 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);
         SweepCrossCompartmentWrappers(cx);
--- a/js/src/jsprobes.cpp
+++ b/js/src/jsprobes.cpp
@@ -64,86 +64,138 @@
 
 using namespace js;
 
 const char Probes::nullName[] = "(null)";
 const char Probes::anonymousName[] = "(anonymous)";
 
 bool Probes::ProfilingActive = true;
 
-#ifdef INCLUDE_MOZILLA_DTRACE
-static const char *
-ScriptFilename(const JSScript *script)
+bool
+Probes::controlProfilers(JSContext *cx, bool toState)
 {
-    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;
-}
+    JSBool ok = JS_TRUE;
+#if defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE)
+    jsval dummy;
+#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;
-}
+    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
+    }
 
-/*
- * 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));
+    ProfilingActive = toState;
+
+    return ok;
 }
 
 void
-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)
+Probes::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,24 +9,20 @@
  * 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.
  *
- * 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.
+ * Copyright (C) 2007  Sun Microsystems, Inc. All Rights Reserved.
  *
  * Contributor(s):
- *      Steve Fink <sfink@mozilla.org>
+ *      Brendan Eich <brendan@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
@@ -43,214 +39,178 @@
 #ifdef INCLUDE_MOZILLA_DTRACE
 #include "javascript-trace.h"
 #endif
 #include "jspubtd.h"
 #include "jsprvtd.h"
 
 namespace js {
 
-namespace Probes {
+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;
+    }
 
-/*
- * 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 *ScriptFilename(const JSScript *script) {
+        if (! script)
+            return "(null)";
+        if (! script->filename)
+            return "(anonymous)";
+        return script->filename;
+    }
 
-/*
- * 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 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;
+    }
 
-/* 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 void current_location(JSContext *cx, int* lineno, char const **filename);
 
-/*
- * 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 const char *FunctionClassname(const JSFunction *fun);
+    static const char *ScriptFilename(JSScript *script);
+    static int FunctionLineNumber(JSContext *cx, const JSFunction *fun);
 
-/* 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);
+    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();
 
-/*
- * 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);
+    /*
+     * 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;
+    }
 
-/*
- * 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 callTrackingActive(JSContext *);
 
-/*
- * String is about to be finalized
- *
- * |string| must still have a valid length.
- */
-bool finalizeString(JSString *string);
+    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);
 
-/* Script is about to be compiled */
-bool compileScriptBegin(JSContext *cx, const char *filename, int lineno);
+    static bool resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
 
-/* Script has just finished compilation */
-bool compileScriptEnd(JSContext *cx, JSScript *script, const char *filename, int lineno);
+    /* |obj| must exist (its class and size are computed) */
+    static bool createObject(JSContext *cx, JSObject *obj);
 
-/* About to make a call from JS into native code */
-bool calloutBegin(JSContext *cx, JSFunction *fun);
+    static bool resizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
 
-/* 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);
+    /* |obj| must still exist (its class is accessed) */
+    static bool finalizeObject(JSObject *obj);
 
-/*
- * 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| 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);
 
-bool GCStartMarkPhase(JSCompartment *compartment);
-bool GCEndMarkPhase(JSCompartment *compartment);
+    /*
+     * |string| must still have a valid length.
+     */
+    static bool finalizeString(JSString *string);
 
-bool GCStartSweepPhase(JSCompartment *compartment);
-bool GCEndSweepPhase(JSCompartment *compartment);
+    static bool compileScriptBegin(JSContext *cx, const char *filename, int lineno);
+    static bool compileScriptEnd(JSContext *cx, JSScript *script, const char *filename, int lineno);
 
-/*
- * 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 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);
 
-/*
- * 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 GCEndMarkPhase(JSCompartment *compartment);
+    static bool GCStartSweepPhase(JSCompartment *compartment);
+    static bool GCEndSweepPhase(JSCompartment *compartment);
 
-/*
- * Internal: ETW-specific probe functions
- */
+    static bool CustomMark(JSString *string);
+    static bool CustomMark(const char *string);
+    static bool CustomMark(int marker);
+
+    static bool startProfiling();
+    static void stopProfiling();
+
 #ifdef MOZ_ETW
-// 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);
+    // 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);
 #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;
@@ -293,23 +253,40 @@ 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())
-        DTraceEnterJSFun(cx, fun, script);
+        enterJSFunImpl(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
@@ -319,17 +296,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())
-        DTraceExitJSFun(cx, fun, script);
+        handleFunctionReturn(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))
@@ -347,30 +324,16 @@ 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);
@@ -689,15 +652,10 @@ 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
@@ -3931,16 +3931,29 @@ 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
@@ -4057,16 +4070,29 @@ 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
@@ -4098,86 +4124,53 @@ 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([profileName])\n"
-"                         Start a profiling session\n"
+"startProfiling()         Start a profiling session.\n"
 "                         Profiler must be running with programatic sampling",
-"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
+"stopProfiling()          Stop a running profiling session\n"
 #endif
 };
 
 #ifdef MOZ_PROFILING
-# 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)
+#define PROFILING_FUNCTION_COUNT 2
 #else
-# define EXTERNAL_FUNCTION_COUNT 0
+#define PROFILING_FUNCTION_COUNT 0
 #endif
 
 /* Help messages must match shell functions. */
-JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) - EXTERNAL_FUNCTION_COUNT ==
+JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) - PROFILING_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) - EXTERNAL_FUNCTION_COUNT; ++m) {
+    for (m = shell_help_messages; m != JS_ARRAY_END(shell_help_messages) - PROFILING_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;
@@ -5190,17 +5183,17 @@ Shell(JSContext *cx, OptionParser *op, c
         if (jsdbc)
             JSDB_TermDebugger(jsdc);
 #endif /* JSDEBUGGER_C_UI */
         JSD_DebuggerOff(jsdc);
     }
 #endif  /* JSDEBUGGER */
 
     if (enableDisassemblyDumps)
-        JS_DumpCompartmentBytecode(cx);
+        JS_DumpAllProfiles(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,16 +286,27 @@ 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,16 +842,21 @@ 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,17 +51,16 @@
 #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
@@ -91,16 +90,27 @@ 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
@@ -109,45 +119,117 @@ static const char* gCurrentProfile;
  *                    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");
 
-    JSBool ok = JS_StartProfiling(profileName);
+    PRBool rv = _PlatformStartProfile(profileName);
     gCurrentProfile = profileName;
-    return ok ? PR_TRUE : PR_FALSE;
+    return rv;
 }
 
 /**
  * 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 JS_StopProfiling(profileName) ? PR_TRUE : PR_FALSE;
+    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;
 }
 
+//--------------------------------------------------
+// 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();
@@ -177,16 +259,20 @@ 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;
       }