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 74372 d7ccb99a2f2d04e406e9f91ff0ecd7dd811a5ed2
parent 74371 aea57f085401d68b3c6e9af301878021f95efabd
child 74373 19ab9ba1c62369998649c5c0192aeafc0b74a230
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
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;
       }