зеркало из https://github.com/mozilla/gecko-dev.git
Back out c8f38fb18c6a (bug 673631) for breaking the Shark shell build
This commit is contained in:
Родитель
0fde035266
Коммит
5bc15911a8
|
@ -2963,6 +2963,25 @@ static JSFunctionSpec JProfFunctions[] = {
|
|||
|
||||
#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},
|
||||
|
@ -2998,6 +3017,16 @@ nsJSContext::InitClasses(void *aGlobalObj)
|
|||
::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);
|
||||
|
|
|
@ -558,6 +558,11 @@ JSFunctionSpec gGlobalFunctions[] =
|
|||
{"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}
|
||||
};
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
* JS debugging API.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "jsprvtd.h"
|
||||
#include "jstypes.h"
|
||||
#include "jsstdint.h"
|
||||
|
@ -1506,251 +1505,32 @@ JS_ClearContextDebugHooks(JSContext *cx)
|
|||
return JS_SetContextDebugHooks(cx, &js_NullDebugHooks);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/* Profiling-related API */
|
||||
|
||||
/* Thread-unsafe error management */
|
||||
|
||||
static char gLastError[2000];
|
||||
|
||||
static void
|
||||
#ifdef _GNU_SOURCE
|
||||
__attribute__((unused,format(printf,1,2)))
|
||||
#endif
|
||||
UnsafeError(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
(void) vsnprintf(gLastError, sizeof(gLastError), format, args);
|
||||
va_end(args);
|
||||
|
||||
gLastError[sizeof(gLastError) - 1] = '\0';
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(const char *)
|
||||
JS_UnsafeGetLastProfilingError()
|
||||
{
|
||||
return gLastError;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_StartProfiling(const char *profileName)
|
||||
JS_StartProfiling()
|
||||
{
|
||||
JSBool ok = JS_TRUE;
|
||||
#if defined(MOZ_SHARK) && defined(__APPLE__)
|
||||
if (!Shark::Start()) {
|
||||
UnsafeError("Failed to start Shark for %s", profileName);
|
||||
ok = JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_VTUNE
|
||||
if (!js_StartVtune(profileName))
|
||||
ok = JS_FALSE;
|
||||
#endif
|
||||
return ok;
|
||||
return Probes::startProfiling();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_StopProfiling(const char *profileName)
|
||||
JS_PUBLIC_API(void)
|
||||
JS_StopProfiling()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start or stop whatever platform- and configuration-specific profiling
|
||||
* backends are available.
|
||||
*/
|
||||
static JSBool
|
||||
ControlProfilers(bool toState)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1765,94 +1545,15 @@ IgnoreAndReturnTrue(JSContext *cx, uintN argc, jsval *vp)
|
|||
|
||||
#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
|
||||
};
|
||||
|
@ -1875,30 +1576,40 @@ JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj)
|
|||
#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()
|
||||
js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
CALLGRIND_STOP_INSTRUMENTATION;
|
||||
return true;
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_DumpCallgrind(const char *outfile)
|
||||
js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
if (outfile) {
|
||||
CALLGRIND_DUMP_STATS_AT(outfile);
|
||||
} else {
|
||||
CALLGRIND_DUMP_STATS;
|
||||
}
|
||||
JSString *str;
|
||||
|
||||
return true;
|
||||
jsval *argv = JS_ARGV(cx, vp);
|
||||
if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
|
||||
str = JSVAL_TO_STRING(argv[0]);
|
||||
JSAutoByteString bytes(cx, str);
|
||||
if (!!bytes) {
|
||||
CALLGRIND_DUMP_STATS_AT(bytes.ptr());
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
CALLGRIND_DUMP_STATS;
|
||||
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#endif /* MOZ_CALLGRIND */
|
||||
|
@ -1933,8 +1644,8 @@ static const char *vtuneErrorMessages[] = {
|
|||
|
||||
};
|
||||
|
||||
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" },
|
||||
|
@ -1961,54 +1672,62 @@ js_StartVtune(const char *profileName)
|
|||
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(¶ms);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2479,29 +2198,32 @@ JS_GetFunctionCallback(JSContext *cx)
|
|||
#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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -500,88 +500,41 @@ JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks);
|
|||
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);
|
||||
JS_StartProfiling();
|
||||
|
||||
/**
|
||||
* Stop any profilers that were previously started with JS_StartProfiling.
|
||||
* Returns true if no profilers fail to stop.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_StopProfiling(const char *profileName);
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_StopProfiling();
|
||||
|
||||
/**
|
||||
* Write the current profile data to the given file, if applicable to whatever
|
||||
* profiler is being used.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_DumpProfile(const char *outfile, const char *profileName);
|
||||
|
||||
/**
|
||||
* Pause currently active profilers (only supported by some profilers). Returns
|
||||
* whether any profilers failed to pause. (Profilers that do not support
|
||||
* pause/resume do not count.)
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_PauseProfilers(const char *profileName);
|
||||
|
||||
/**
|
||||
* Resume suspended profilers
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_ResumeProfilers(const char *profileName);
|
||||
|
||||
/**
|
||||
* Add various profiling-related functions as properties of the given object.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj);
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
|
||||
|
@ -615,10 +568,10 @@ 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
|
||||
|
||||
|
|
|
@ -2202,6 +2202,7 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
|
|||
(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)
|
||||
|
@ -2336,7 +2337,6 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
|||
* unreachable compartments.
|
||||
*/
|
||||
if (comp) {
|
||||
Probes::GCStartSweepPhase(comp);
|
||||
comp->sweep(cx, 0);
|
||||
comp->finalizeObjectArenaLists(cx);
|
||||
GCTIMESTAMP(sweepObjectEnd);
|
||||
|
@ -2344,7 +2344,6 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
|||
GCTIMESTAMP(sweepStringEnd);
|
||||
comp->finalizeShapeArenaLists(cx);
|
||||
GCTIMESTAMP(sweepShapeEnd);
|
||||
Probes::GCEndSweepPhase(comp);
|
||||
} else {
|
||||
/*
|
||||
* Some sweeping is not compartment-specific. Start a NULL-compartment
|
||||
|
|
|
@ -69,65 +69,48 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* These functions call the DTrace macros for the JavaScript USDT probes.
|
||||
* Originally this code was inlined in the JavaScript code; however since
|
||||
* a number of operations are called, these have been placed into functions
|
||||
* to reduce any negative compiler optimization effect that the addition of
|
||||
* a number of usually unused lines of code would cause.
|
||||
*/
|
||||
void
|
||||
Probes::DTraceEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
|
||||
{
|
||||
JSAutoByteString funNameBytes;
|
||||
JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), FunctionClassname(fun),
|
||||
FunctionName(cx, fun, &funNameBytes));
|
||||
}
|
||||
|
||||
void
|
||||
Probes::DTraceExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
|
||||
{
|
||||
JSAutoByteString funNameBytes;
|
||||
JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), FunctionClassname(fun),
|
||||
FunctionName(cx, fun, &funNameBytes));
|
||||
}
|
||||
JSBool ok = JS_TRUE;
|
||||
#if defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE)
|
||||
jsval dummy;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
static void
|
||||
current_location(JSContext *cx, int* lineno, char const **filename)
|
||||
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
|
||||
}
|
||||
|
||||
ProfilingActive = toState;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
Probes::current_location(JSContext *cx, int* lineno, char const **filename)
|
||||
{
|
||||
JSScript *script = js_GetCurrentScript(cx);
|
||||
if (! script) {
|
||||
|
@ -139,6 +122,75 @@ current_location(JSContext *cx, int* lineno, char const **filename)
|
|||
*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)
|
||||
*
|
||||
|
|
|
@ -14,14 +14,10 @@
|
|||
* 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"),
|
||||
|
@ -48,204 +44,168 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
namespace Probes {
|
||||
class Probes {
|
||||
static bool ProfilingActive;
|
||||
static bool controlProfilers(JSContext *cx, bool toState);
|
||||
|
||||
/*
|
||||
* 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 nullName[];
|
||||
static const char anonymousName[];
|
||||
|
||||
/*
|
||||
* Internal use only: remember whether "profiling", whatever that means, is
|
||||
* currently active. Used for state management.
|
||||
*/
|
||||
extern bool ProfilingActive;
|
||||
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;
|
||||
}
|
||||
|
||||
extern const char nullName[];
|
||||
extern const char anonymousName[];
|
||||
static const char *ScriptFilename(const JSScript *script) {
|
||||
if (! script)
|
||||
return "(null)";
|
||||
if (! script->filename)
|
||||
return "(anonymous)";
|
||||
return script->filename;
|
||||
}
|
||||
|
||||
/* JSRuntime created, with currently valid fields */
|
||||
bool createRuntime(JSRuntime *rt);
|
||||
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 about to be destroyed */
|
||||
bool destroyRuntime(JSRuntime *rt);
|
||||
static void current_location(JSContext *cx, int* lineno, char const **filename);
|
||||
|
||||
/* Total JS engine shutdown */
|
||||
bool shutdown();
|
||||
static const char *FunctionClassname(const JSFunction *fun);
|
||||
static const char *ScriptFilename(JSScript *script);
|
||||
static int FunctionLineNumber(JSContext *cx, const JSFunction *fun);
|
||||
|
||||
/*
|
||||
* Test whether we are tracking JS function call enter/exit. The JITs use this
|
||||
* to decide whether they can optimize in a way that would prevent probes from
|
||||
* firing.
|
||||
*/
|
||||
bool callTrackingActive(JSContext *);
|
||||
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();
|
||||
|
||||
/* Entering a JS function */
|
||||
bool enterJSFun(JSContext *, JSFunction *, JSScript *, int counter = 1);
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* About to leave a JS function */
|
||||
bool exitJSFun(JSContext *, JSFunction *, JSScript *, int counter = 0);
|
||||
static bool callTrackingActive(JSContext *);
|
||||
|
||||
/* Executing a script */
|
||||
bool startExecution(JSContext *cx, JSScript *script);
|
||||
static bool enterJSFun(JSContext *, JSFunction *, JSScript *, int counter = 1);
|
||||
static bool exitJSFun(JSContext *, JSFunction *, JSScript *, int counter = 0);
|
||||
|
||||
/* Script has completed execution */
|
||||
bool stopExecution(JSContext *cx, JSScript *script);
|
||||
static bool startExecution(JSContext *cx, JSScript *script);
|
||||
static bool stopExecution(JSContext *cx, JSScript *script);
|
||||
|
||||
/* Heap has been resized */
|
||||
bool resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
|
||||
static bool resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
|
||||
|
||||
/*
|
||||
* Object has been created. |obj| must exist (its class and size are read)
|
||||
*/
|
||||
bool createObject(JSContext *cx, JSObject *obj);
|
||||
/* |obj| must exist (its class and size are computed) */
|
||||
static bool createObject(JSContext *cx, JSObject *obj);
|
||||
|
||||
/* Object has been resized */
|
||||
bool resizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
|
||||
static 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);
|
||||
/* |obj| must still exist (its class is accessed) */
|
||||
static bool finalizeObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
/*
|
||||
* |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);
|
||||
|
||||
/*
|
||||
* String is about to be finalized
|
||||
*
|
||||
* |string| must still have a valid length.
|
||||
*/
|
||||
bool finalizeString(JSString *string);
|
||||
/*
|
||||
* |string| must still have a valid length.
|
||||
*/
|
||||
static bool finalizeString(JSString *string);
|
||||
|
||||
/* Script is about to be compiled */
|
||||
bool compileScriptBegin(JSContext *cx, const char *filename, int lineno);
|
||||
static bool compileScriptBegin(JSContext *cx, const char *filename, int lineno);
|
||||
static bool compileScriptEnd(JSContext *cx, JSScript *script, const char *filename, int lineno);
|
||||
|
||||
/* Script has just finished compilation */
|
||||
bool compileScriptEnd(JSContext *cx, JSScript *script, const char *filename, int lineno);
|
||||
static bool calloutBegin(JSContext *cx, JSFunction *fun);
|
||||
static bool calloutEnd(JSContext *cx, JSFunction *fun);
|
||||
|
||||
/* About to make a call from JS into native code */
|
||||
bool calloutBegin(JSContext *cx, JSFunction *fun);
|
||||
static bool acquireMemory(JSContext *cx, void *address, size_t nbytes);
|
||||
static bool releaseMemory(JSContext *cx, void *address, size_t nbytes);
|
||||
|
||||
/* Native code called by JS has terminated */
|
||||
bool calloutEnd(JSContext *cx, JSFunction *fun);
|
||||
static bool GCStart(JSCompartment *compartment);
|
||||
static bool GCEnd(JSCompartment *compartment);
|
||||
static bool GCStartMarkPhase(JSCompartment *compartment);
|
||||
|
||||
/* Unimplemented */
|
||||
bool acquireMemory(JSContext *cx, void *address, size_t nbytes);
|
||||
bool releaseMemory(JSContext *cx, void *address, size_t nbytes);
|
||||
static bool GCEndMarkPhase(JSCompartment *compartment);
|
||||
static bool GCStartSweepPhase(JSCompartment *compartment);
|
||||
static bool GCEndSweepPhase(JSCompartment *compartment);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
static bool CustomMark(JSString *string);
|
||||
static bool CustomMark(const char *string);
|
||||
static bool CustomMark(int marker);
|
||||
|
||||
bool GCStartMarkPhase(JSCompartment *compartment);
|
||||
bool GCEndMarkPhase(JSCompartment *compartment);
|
||||
static bool startProfiling();
|
||||
static void stopProfiling();
|
||||
|
||||
bool GCStartSweepPhase(JSCompartment *compartment);
|
||||
bool GCEndSweepPhase(JSCompartment *compartment);
|
||||
|
||||
/*
|
||||
* Various APIs for inserting custom probe points. These might be used to mark
|
||||
* when something starts and stops, or for various other purposes the user has
|
||||
* in mind. These are useful to export to JS so that JS code can mark
|
||||
* application-meaningful events and phases of execution.
|
||||
*
|
||||
* Not all backends support these.
|
||||
*/
|
||||
bool CustomMark(JSString *string);
|
||||
bool CustomMark(const char *string);
|
||||
bool CustomMark(int marker);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Internal: ETW-specific probe functions
|
||||
*/
|
||||
#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)
|
||||
|
@ -298,13 +258,30 @@ Probes::callTrackingActive(JSContext *cx)
|
|||
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);
|
||||
|
@ -324,7 +301,7 @@ Probes::exitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
|
|||
|
||||
#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)
|
||||
|
@ -352,20 +329,6 @@ Probes::resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize)
|
|||
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)
|
||||
{
|
||||
|
@ -694,10 +657,5 @@ struct AutoFunctionCallProbe {
|
|||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* Internal functions for controlling various profilers. The profiler-specific
|
||||
* implementations of these are mostly in jsdbgapi.cpp.
|
||||
*/
|
||||
|
||||
|
||||
#endif /* _JSPROBES_H */
|
||||
|
|
|
@ -3936,6 +3936,19 @@ static JSFunctionSpec shell_functions[] = {
|
|||
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),
|
||||
|
@ -4062,6 +4075,19 @@ static const char *const shell_help_messages[] = {
|
|||
"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",
|
||||
|
@ -4103,50 +4129,20 @@ static const char *const shell_help_messages[] = {
|
|||
|
||||
/* 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
|
||||
|
@ -4157,7 +4153,7 @@ CheckHelpMessages()
|
|||
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,
|
||||
|
@ -4170,9 +4166,6 @@ CheckHelpMessages()
|
|||
#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)
|
||||
|
@ -5195,7 +5188,7 @@ Shell(JSContext *cx, OptionParser *op, char **envp)
|
|||
#endif /* JSDEBUGGER */
|
||||
|
||||
if (enableDisassemblyDumps)
|
||||
JS_DumpCompartmentBytecode(cx);
|
||||
JS_DumpAllProfiles(cx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -291,6 +291,17 @@ static JSFunctionSpec gGlobalFun[] = {
|
|||
{"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},
|
||||
|
|
|
@ -847,6 +847,11 @@ static JSFunctionSpec glob_functions[] = {
|
|||
#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}
|
||||
};
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
#include "nsIFile.h"
|
||||
#include "nsIProperties.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -96,6 +95,17 @@ void passed(const char* 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
|
||||
|
@ -114,12 +124,19 @@ static const char* gCurrentProfile;
|
|||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,13 +153,78 @@ StartProfiling(const char* profileName)
|
|||
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
|
||||
|
@ -182,6 +264,10 @@ class ScopedXPCOM : public nsIDirectoryServiceProvider2
|
|||
|
||||
~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)))
|
||||
|
|
Загрузка…
Ссылка в новой задаче