From 571bfdff48498f1b0014de8a5ba27c637b999877 Mon Sep 17 00:00:00 2001 From: Mark Steele Date: Thu, 30 Jul 2009 11:48:02 -0700 Subject: [PATCH] Bug 497999: collect context-specific TraceVis data in JS objects, r=jorendorff --- config/autoconf.mk.in | 1 + configure.in | 11 + dom/base/nsJSEnvironment.cpp | 13 + js/src/jsdbgapi.cpp | 432 ++++++++++++++++++ js/src/jsdbgapi.h | 9 + js/src/jsinterp.cpp | 13 +- js/src/jstracer.cpp | 9 +- js/src/jstracer.h | 29 +- .../xpconnect/loader/mozJSComponentLoader.cpp | 6 +- 9 files changed, 505 insertions(+), 18 deletions(-) diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 51f26fba0bf..3f7aff9b261 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -112,6 +112,7 @@ MOZ_JPROF = @MOZ_JPROF@ MOZ_SHARK = @MOZ_SHARK@ MOZ_CALLGRIND = @MOZ_CALLGRIND@ MOZ_VTUNE = @MOZ_VTUNE@ +MOZ_TRACEVIS = @MOZ_TRACEVIS@ DEHYDRA_PATH = @DEHYDRA_PATH@ MOZ_XPCTOOLS = @MOZ_XPCTOOLS@ diff --git a/configure.in b/configure.in index a7751997ba7..b187e8832cf 100644 --- a/configure.in +++ b/configure.in @@ -6697,6 +6697,17 @@ MOZ_ARG_WITH_STRING(wrap-malloc, [ --with-wrap-malloc=DIR Location of malloc wrapper library], WRAP_MALLOC_LIB=$withval) +dnl ======================================================== +dnl = Use TraceVis +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(tracevis, +[ --enable-tracevis Enable TraceVis tracing tool (default=no)], + MOZ_TRACEVIS=1, + MOZ_TRACEVIS= ) +if test -n "$MOZ_TRACEVIS"; then + AC_DEFINE(MOZ_TRACEVIS) +fi + dnl ======================================================== dnl = Use Valgrind dnl ======================================================== diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 72ba57e8cc7..649a7efb70a 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -3269,6 +3269,14 @@ static JSFunctionSpec VtuneFunctions[] = { }; #endif +#ifdef MOZ_TRACEVIS +static JSFunctionSpec EthogramFunctions[] = { + {"initEthogram", js_InitEthogram, 0, 0, 0}, + {"shutdownEthogram", js_ShutdownEthogram, 0, 0, 0}, + {nsnull, nsnull, 0, 0, 0} +}; +#endif + nsresult nsJSContext::InitClasses(void *aGlobalObj) { @@ -3316,6 +3324,11 @@ nsJSContext::InitClasses(void *aGlobalObj) ::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; diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index fd6af3ee7dc..730a9d97bee 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -2012,3 +2012,435 @@ js_ResumeVtune(JSContext *cx, JSObject *obj, } #endif /* MOZ_VTUNE */ + +#ifdef MOZ_TRACEVIS +/* + * Ethogram - Javascript wrapper for TraceVis state + * + * ethology: The scientific study of animal behavior, + * especially as it occurs in a natural environment. + * ethogram: A pictorial catalog of the behavioral patterns of + * an organism or a species. + * + */ +#if defined(XP_WIN) +#include +#else +#include +#endif +#include "jstracer.h" + +#define ETHOGRAM_BUF_SIZE 65536 + +static JSBool +ethogram_construct(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval); +static void +ethogram_finalize(JSContext *cx, JSObject *obj); + +static JSClass ethogram_class = { + "Ethogram", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ethogram_finalize, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +struct EthogramEvent { + TraceVisState s; + TraceVisExitReason r; + int ts; + int tus; + JSString *filename; + int lineno; +}; + +static int +compare_strings(const void *k1, const void *k2) +{ + return strcmp((const char *) k1, (const char *) k2) == 0; +} + +class EthogramEventBuffer { +private: + EthogramEvent mBuf[ETHOGRAM_BUF_SIZE]; + int mReadPos; + int mWritePos; + JSObject *mFilenames; + int mStartSecond; + + struct EthogramScriptEntry { + char *filename; + JSString *jsfilename; + + EthogramScriptEntry *next; + }; + EthogramScriptEntry *mScripts; + +public: + friend JSBool + ethogram_construct(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval); + + inline void push(TraceVisState s, TraceVisExitReason r, char *filename, int lineno) { + mBuf[mWritePos].s = s; + mBuf[mWritePos].r = r; +#if defined(XP_WIN) + FILETIME now; + GetSystemTimeAsFileTime(&now); + unsigned long long raw_us = 0.1 * + (((unsigned long long) now.dwHighDateTime << 32ULL) | + (unsigned long long) now.dwLowDateTime); + unsigned int sec = raw_us / 1000000L; + unsigned int usec = raw_us % 1000000L; + mBuf[mWritePos].ts = sec - mStartSecond; + mBuf[mWritePos].tus = usec; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + mBuf[mWritePos].ts = tv.tv_sec - mStartSecond; + mBuf[mWritePos].tus = tv.tv_usec; +#endif + + JSString *jsfilename = findScript(filename); + mBuf[mWritePos].filename = jsfilename; + mBuf[mWritePos].lineno = lineno; + + mWritePos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE; + if (mWritePos == mReadPos) { + mReadPos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE; + } + } + + inline EthogramEvent *pop() { + EthogramEvent *e = &mBuf[mReadPos]; + mReadPos = (mReadPos + 1) % ETHOGRAM_BUF_SIZE; + return e; + } + + bool isEmpty() { + return (mReadPos == mWritePos); + } + + EthogramScriptEntry *addScript(JSContext *cx, JSObject *obj, char *filename, JSString *jsfilename) { + JSHashNumber hash = JS_HashString(filename); + JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename); + if (*hep != NULL) + return JS_FALSE; + + JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this); + + EthogramScriptEntry * entry = (EthogramScriptEntry *) JS_malloc(cx, sizeof(EthogramScriptEntry)); + if (entry == NULL) + return NULL; + + entry->next = mScripts; + mScripts = entry; + entry->filename = filename; + entry->jsfilename = jsfilename; + + return mScripts; + } + + void removeScripts(JSContext *cx) { + EthogramScriptEntry *se = mScripts; + while (se != NULL) { + char *filename = se->filename; + + JSHashNumber hash = JS_HashString(filename); + JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename); + JSHashEntry *he = *hep; + if (he) { + /* we hardly knew he */ + JS_HashTableRawRemove(traceVisScriptTable, hep, he); + } + + EthogramScriptEntry *se_head = se; + se = se->next; + JS_free(cx, se_head); + } + } + + JSString *findScript(char *filename) { + EthogramScriptEntry *se = mScripts; + while (se != NULL) { + if (compare_strings(se->filename, filename)) + return (se->jsfilename); + se = se->next; + } + return NULL; + } + + JSObject *filenames() { + return mFilenames; + } + + int length() { + if (mWritePos < mReadPos) + return (mWritePos + ETHOGRAM_BUF_SIZE) - mReadPos; + else + return mWritePos - mReadPos; + } +}; + +static char jstv_empty[] = ""; + +inline char * +jstv_Filename(JSStackFrame *fp) +{ + while (fp && fp->script == NULL) + fp = fp->down; + return (fp && fp->script && fp->script->filename) + ? (char *)fp->script->filename + : jstv_empty; +} +inline uintN +jstv_Lineno(JSContext *cx, JSStackFrame *fp) +{ + while (fp && fp->regs == NULL) + fp = fp->down; + return (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0; +} + +/* Collect states here and distribute to a matching buffer, if any */ +JS_FRIEND_API(void) +js_StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r) +{ + JSStackFrame *fp = cx->fp; + + char *script_file = jstv_Filename(fp); + JSHashNumber hash = JS_HashString(script_file); + + JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, script_file); + /* update event buffer, flag if overflowed */ + JSHashEntry *he = *hep; + if (he) { + EthogramEventBuffer *p; + p = (EthogramEventBuffer *) he->value; + + p->push(s, r, script_file, jstv_Lineno(cx, fp)); + } +} + +static JSBool +ethogram_construct(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + EthogramEventBuffer *p; + + p = (EthogramEventBuffer *) JS_malloc(cx, sizeof(EthogramEventBuffer)); + + p->mReadPos = p->mWritePos = 0; + p->mScripts = NULL; + p->mFilenames = JS_NewArrayObject(cx, 0, NULL); + +#if defined(XP_WIN) + FILETIME now; + GetSystemTimeAsFileTime(&now); + unsigned long long raw_us = 0.1 * + (((unsigned long long) now.dwHighDateTime << 32ULL) | + (unsigned long long) now.dwLowDateTime); + unsigned int s = raw_us / 1000000L; + p->mStartSecond = s; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + p->mStartSecond = tv.tv_sec; +#endif + jsval filenames = OBJECT_TO_JSVAL(p->filenames()); + if (!JS_DefineProperty(cx, obj, "filenames", filenames, + NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT)) + return JS_FALSE; + + if (!JS_IsConstructing(cx)) { + obj = JS_NewObject(cx, ðogram_class, NULL, NULL); + if (!obj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(obj); + } + JS_SetPrivate(cx, obj, p); + return JS_TRUE; +} + +static void +ethogram_finalize(JSContext *cx, JSObject *obj) +{ + EthogramEventBuffer *p; + p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, NULL); + if (!p) + return; + + p->removeScripts(cx); + + JS_free(cx, p); +} + +static JSBool +ethogram_addScript(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + JSString *str; + char *filename = NULL; + if (argc > 0 && JSVAL_IS_STRING(argv[0])) { + str = JSVAL_TO_STRING(argv[0]); + filename = js_DeflateString(cx, + str->chars(), + str->length()); + } + + /* silently ignore no args */ + if (!filename) + return JS_TRUE; + + EthogramEventBuffer *p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, argv); + + p->addScript(cx, obj, filename, str); + JS_CallFunctionName(cx, p->filenames(), "push", 1, argv, rval); + return JS_TRUE; +} + +static JSBool +ethogram_getAllEvents(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + EthogramEventBuffer *p; + + p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, argv); + if (!p) + return JS_FALSE; + + if (p->isEmpty()) { + *rval = JSVAL_NULL; + return JS_TRUE; + } + + JSObject *rarray = JS_NewArrayObject(cx, 0, NULL); + if (rarray == NULL) { + *rval = JSVAL_NULL; + return JS_TRUE; + } + + *rval = OBJECT_TO_JSVAL(rarray); + + for (int i = 0; !p->isEmpty(); i++) { + + JSObject *x = JS_NewObject(cx, NULL, NULL, NULL); + if (x == NULL) + return JS_FALSE; + + EthogramEvent *e = p->pop(); + + jsval state = INT_TO_JSVAL(e->s); + jsval reason = INT_TO_JSVAL(e->r); + jsval ts = INT_TO_JSVAL(e->ts); + jsval tus = INT_TO_JSVAL(e->tus); + + jsval filename = STRING_TO_JSVAL(e->filename); + jsval lineno = INT_TO_JSVAL(e->lineno); + + if (!JS_SetProperty(cx, x, "state", &state)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "reason", &reason)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "ts", &ts)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "tus", &tus)) + return JS_FALSE; + + if (!JS_SetProperty(cx, x, "filename", &filename)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "lineno", &lineno)) + return JS_FALSE; + + jsval element = OBJECT_TO_JSVAL(x); + JS_SetElement(cx, rarray, i, &element); + } + + return JS_TRUE; +} + +static JSBool +ethogram_getNextEvent(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + EthogramEventBuffer *p; + + p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, argv); + if (!p) + return JS_FALSE; + + JSObject *x = JS_NewObject(cx, NULL, NULL, NULL); + if (x == NULL) + return JS_FALSE; + + if (p->isEmpty()) { + *rval = JSVAL_NULL; + return JS_TRUE; + } + + EthogramEvent *e = p->pop(); + jsval state = INT_TO_JSVAL(e->s); + jsval reason = INT_TO_JSVAL(e->r); + jsval ts = INT_TO_JSVAL(e->ts); + jsval tus = INT_TO_JSVAL(e->tus); + + jsval filename = STRING_TO_JSVAL(e->filename); + jsval lineno = INT_TO_JSVAL(e->lineno); + + if (!JS_SetProperty(cx, x, "state", &state)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "reason", &reason)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "ts", &ts)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "tus", &tus)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "filename", &filename)) + return JS_FALSE; + + if (!JS_SetProperty(cx, x, "lineno", &lineno)) + return JS_FALSE; + + *rval = OBJECT_TO_JSVAL(x); + + return JS_TRUE; +} + +static JSFunctionSpec ethogram_methods[] = { + {"addScript", ethogram_addScript, 1}, + {"getAllEvents", ethogram_getAllEvents, 0}, + {"getNextEvent", ethogram_getNextEvent, 0}, + {0} +}; + +/* + * An |Ethogram| organizes the output of a collection of files that should be + * monitored together. A single object gets events for the group. + */ +JS_FRIEND_API(JSBool) +js_InitEthogram(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + if (!traceVisScriptTable) { + traceVisScriptTable = JS_NewHashTable(8, JS_HashString, compare_strings, + NULL, NULL, NULL); + } + + JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, ðogram_class, + ethogram_construct, 0, NULL, ethogram_methods, + NULL, NULL); + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_ShutdownEthogram(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + if (traceVisScriptTable) + JS_HashTableDestroy(traceVisScriptTable); + + return JS_TRUE; +} + +#endif /* MOZ_TRACEVIS */ diff --git a/js/src/jsdbgapi.h b/js/src/jsdbgapi.h index b6855b25593..597bba5a85a 100644 --- a/js/src/jsdbgapi.h +++ b/js/src/jsdbgapi.h @@ -495,6 +495,15 @@ js_ResumeVtune(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, #endif /* MOZ_VTUNE */ +#ifdef MOZ_TRACEVIS +extern JS_FRIEND_API(JSBool) +js_InitEthogram(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval); +extern JS_FRIEND_API(JSBool) +js_ShutdownEthogram(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval); +#endif /* MOZ_TRACEVIS */ + JS_END_EXTERN_C #endif /* jsdbgapi_h___ */ diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 88f81427abc..271c5fed699 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -2664,7 +2664,7 @@ JS_REQUIRES_STACK JSBool js_Interpret(JSContext *cx) { #ifdef MOZ_TRACEVIS - TraceVisStateObj tvso(S_INTERP); + TraceVisStateObj tvso(cx, S_INTERP); #endif JSRuntime *rt; @@ -2880,11 +2880,18 @@ js_Interpret(JSContext *cx) #ifdef JS_TRACER #ifdef MOZ_TRACEVIS +#if JS_THREADED_INTERP #define MONITOR_BRANCH_TRACEVIS \ JS_BEGIN_MACRO \ if (jumpTable != interruptJumpTable) \ - js_EnterTraceVisState(S_RECORD, R_NONE); \ + js_EnterTraceVisState(cx, S_RECORD, R_NONE); \ JS_END_MACRO +#else /* !JS_THREADED_INTERP */ +#define MONITOR_BRANCH_TRACEVIS \ + JS_BEGIN_MACRO \ + js_EnterTraceVisState(cx, S_RECORD, R_NONE); \ + JS_END_MACRO +#endif #else #define MONITOR_BRANCH_TRACEVIS #endif @@ -3115,7 +3122,7 @@ js_Interpret(JSContext *cx) #if JS_THREADED_INTERP #ifdef MOZ_TRACEVIS if (!moreInterrupts) - js_ExitTraceVisState(R_ABORT); + js_ExitTraceVisState(cx, R_ABORT); #endif jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable; JS_EXTENSION_(goto *normalJumpTable[op]); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 8b6d957cd93..9115ad52251 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -3729,7 +3729,7 @@ JS_REQUIRES_STACK void TraceRecorder::compile(JSTraceMonitor* tm) { #ifdef MOZ_TRACEVIS - TraceVisStateObj tvso(S_COMPILE); + TraceVisStateObj tvso(cx, S_COMPILE); #endif if (tm->needFlush) { @@ -5427,7 +5427,7 @@ ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount, VMSideExit** innermostNestedGuardp) { #ifdef MOZ_TRACEVIS - TraceVisStateObj tvso(S_EXECUTE); + TraceVisStateObj tvso(cx, S_EXECUTE); #endif JS_ASSERT(f->root == f && f->code() && f->vmprivate); @@ -5525,7 +5525,7 @@ ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount, // TraceVisStateObj constructors and destructors must run at the right times. { #ifdef MOZ_TRACEVIS - TraceVisStateObj tvso_n(S_NATIVE); + TraceVisStateObj tvso_n(cx, S_NATIVE); #endif #if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32) SIMULATE_FASTCALL(rec, state, NULL, u.func); @@ -5837,7 +5837,7 @@ JS_REQUIRES_STACK bool js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount) { #ifdef MOZ_TRACEVIS - TraceVisStateObj tvso(S_MONITOR); + TraceVisStateObj tvso(cx, S_MONITOR); #endif JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); @@ -12732,6 +12732,7 @@ DumpPeerStability(JSTraceMonitor* tm, const void* ip, JSObject* globalObj, uint3 #ifdef MOZ_TRACEVIS FILE* traceVisLogFile = NULL; +JSHashTable *traceVisScriptTable = NULL; JS_FRIEND_API(bool) JS_StartTraceVis(const char* filename = "tracevis.dat") diff --git a/js/src/jstracer.h b/js/src/jstracer.h index a91c7c87ec3..019c4f12e2d 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -1005,14 +1005,18 @@ enum TraceVisExitReason { R_OTHER_EXIT }; -const unsigned long long MS64_MASK = 0xfllu << 60; -const unsigned long long MR64_MASK = 0x1fllu << 55; +const unsigned long long MS64_MASK = 0xfull << 60; +const unsigned long long MR64_MASK = 0x1full << 55; const unsigned long long MT64_MASK = ~(MS64_MASK | MR64_MASK); extern FILE* traceVisLogFile; +extern JSHashTable *traceVisScriptTable; + +extern JS_FRIEND_API(void) +js_StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r); static inline void -js_LogTraceVisState(TraceVisState s, TraceVisExitReason r) +js_LogTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r) { if (traceVisLogFile) { unsigned long long sllu = s; @@ -1020,30 +1024,35 @@ js_LogTraceVisState(TraceVisState s, TraceVisExitReason r) unsigned long long d = (sllu << 60) | (rllu << 55) | (rdtsc() & MT64_MASK); fwrite(&d, sizeof(d), 1, traceVisLogFile); } + if (traceVisScriptTable) { + js_StoreTraceVisState(cx, s, r); + } } static inline void -js_EnterTraceVisState(TraceVisState s, TraceVisExitReason r) +js_EnterTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r) { - js_LogTraceVisState(s, r); + js_LogTraceVisState(cx, s, r); } static inline void -js_ExitTraceVisState(TraceVisExitReason r) +js_ExitTraceVisState(JSContext *cx, TraceVisExitReason r) { - js_LogTraceVisState(S_EXITLAST, r); + js_LogTraceVisState(cx, S_EXITLAST, r); } struct TraceVisStateObj { TraceVisExitReason r; + JSContext *mCx; - inline TraceVisStateObj(TraceVisState s) : r(R_NONE) + inline TraceVisStateObj(JSContext *cx, TraceVisState s) : r(R_NONE) { - js_EnterTraceVisState(s, R_NONE); + js_EnterTraceVisState(cx, s, R_NONE); + mCx = cx; } inline ~TraceVisStateObj() { - js_ExitTraceVisState(r); + js_ExitTraceVisState(mCx, r); } }; diff --git a/js/src/xpconnect/loader/mozJSComponentLoader.cpp b/js/src/xpconnect/loader/mozJSComponentLoader.cpp index 704eeb85ef4..53ab84a1883 100644 --- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp @@ -83,7 +83,7 @@ #include "prmem.h" #include "plbase64.h" -#if defined(MOZ_SHARK) || defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE) +#if defined(MOZ_SHARK) || defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE) || defined(MOZ_TRACEVIS) #include "jsdbgapi.h" #endif @@ -291,6 +291,10 @@ static JSFunctionSpec gGlobalFun[] = { {"stopVtune", js_StopVtune, 0,0,0}, {"pauseVtune", js_PauseVtune, 0,0,0}, {"resumeVtune", js_ResumeVtune, 0,0,0}, +#endif +#ifdef MOZ_TRACEVIS + {"initEthogram", js_InitEthogram, 0,0,0}, + {"shutdownEthogram", js_ShutdownEthogram, 0,0,0}, #endif {nsnull,nsnull,0,0,0} };