зеркало из https://github.com/mozilla/gecko-dev.git
Merge tracemonkey to mozilla-central.
This commit is contained in:
Коммит
21991120d1
|
@ -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@
|
||||
|
|
11
configure.in
11
configure.in
|
@ -6703,6 +6703,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 ========================================================
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -284,43 +284,55 @@ struct JSTraceableNative {
|
|||
*/
|
||||
#define JS_DEFINE_CALLINFO_1(linkage, rt, op, at0, cse, fold) \
|
||||
_JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), (_JS_CTYPE_TYPE(at0)), \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << 2) | _JS_CTYPE_RETSIZE(rt), cse, fold)
|
||||
(_JS_CTYPE_ARGSIZE(at0) << (1*nanojit::ARGSIZE_SHIFT)) | \
|
||||
_JS_CTYPE_RETSIZE(rt), cse, fold)
|
||||
#define JS_DEFINE_CALLINFO_2(linkage, rt, op, at0, at1, cse, fold) \
|
||||
_JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \
|
||||
(_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1)), \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << 4) | (_JS_CTYPE_ARGSIZE(at1) << 2) | \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << (2*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at1) << (1*nanojit::ARGSIZE_SHIFT)) | \
|
||||
_JS_CTYPE_RETSIZE(rt), \
|
||||
cse, fold)
|
||||
#define JS_DEFINE_CALLINFO_3(linkage, rt, op, at0, at1, at2, cse, fold) \
|
||||
_JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \
|
||||
(_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2)), \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << 6) | (_JS_CTYPE_ARGSIZE(at1) << 4) | \
|
||||
(_JS_CTYPE_ARGSIZE(at2) << 2) | _JS_CTYPE_RETSIZE(rt), \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << (3*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at1) << (2*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at2) << (1*nanojit::ARGSIZE_SHIFT)) | \
|
||||
_JS_CTYPE_RETSIZE(rt), \
|
||||
cse, fold)
|
||||
#define JS_DEFINE_CALLINFO_4(linkage, rt, op, at0, at1, at2, at3, cse, fold) \
|
||||
_JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \
|
||||
(_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \
|
||||
_JS_CTYPE_TYPE(at3)), \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << 8) | (_JS_CTYPE_ARGSIZE(at1) << 6) | \
|
||||
(_JS_CTYPE_ARGSIZE(at2) << 4) | (_JS_CTYPE_ARGSIZE(at3) << 2) | \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << (4*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at1) << (3*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at2) << (2*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at3) << (1*nanojit::ARGSIZE_SHIFT)) | \
|
||||
_JS_CTYPE_RETSIZE(rt), \
|
||||
cse, fold)
|
||||
#define JS_DEFINE_CALLINFO_5(linkage, rt, op, at0, at1, at2, at3, at4, cse, fold) \
|
||||
_JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \
|
||||
(_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \
|
||||
_JS_CTYPE_TYPE(at3), _JS_CTYPE_TYPE(at4)), \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << 10) | (_JS_CTYPE_ARGSIZE(at1) << 8) | \
|
||||
(_JS_CTYPE_ARGSIZE(at2) << 6) | (_JS_CTYPE_ARGSIZE(at3) << 4) | \
|
||||
(_JS_CTYPE_ARGSIZE(at4) << 2) | _JS_CTYPE_RETSIZE(rt), \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << (5*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at1) << (4*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at2) << (3*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at3) << (2*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at4) << (1*nanojit::ARGSIZE_SHIFT)) | \
|
||||
_JS_CTYPE_RETSIZE(rt), \
|
||||
cse, fold)
|
||||
|
||||
#define JS_DEFINE_CALLINFO_6(linkage, rt, op, at0, at1, at2, at3, at4, at5, cse, fold) \
|
||||
_JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \
|
||||
(_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \
|
||||
_JS_CTYPE_TYPE(at3), _JS_CTYPE_TYPE(at4), _JS_CTYPE_TYPE(at5)), \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << 12) | (_JS_CTYPE_ARGSIZE(at1) << 10) | \
|
||||
(_JS_CTYPE_ARGSIZE(at2) << 8) | (_JS_CTYPE_ARGSIZE(at3) << 6) | \
|
||||
(_JS_CTYPE_ARGSIZE(at4) << 4) | (_JS_CTYPE_ARGSIZE(at5) << 2) | \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << (6*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at1) << (5*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at2) << (4*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at3) << (3*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at4) << (2*nanojit::ARGSIZE_SHIFT)) | \
|
||||
(_JS_CTYPE_ARGSIZE(at5) << (1*nanojit::ARGSIZE_SHIFT)) | \
|
||||
_JS_CTYPE_RETSIZE(rt), cse, fold)
|
||||
|
||||
#define JS_DECLARE_CALLINFO(name) extern const nanojit::CallInfo _JS_CALLINFO(name);
|
||||
|
|
|
@ -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 <windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#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[] = "<null>";
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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___ */
|
||||
|
|
|
@ -2519,20 +2519,16 @@ js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
|
|||
? JS_SCRIPT_UPVARS(fun->u.i.script)->length
|
||||
: 0) == fun->u.i.nupvars);
|
||||
|
||||
/*
|
||||
* Assert that fun->countInterpretedReservedSlots returns 0 when
|
||||
* fun->u.i.nupvars is zero.
|
||||
*/
|
||||
JS_ASSERT(fun->u.i.script->regexpsOffset == 0);
|
||||
|
||||
JSObject *closure = js_CloneFunctionObject(cx, fun, scopeChain);
|
||||
if (!closure || fun->u.i.nupvars == 0)
|
||||
if (!closure)
|
||||
return closure;
|
||||
if (!js_EnsureReservedSlots(cx, closure,
|
||||
fun->countInterpretedReservedSlots())) {
|
||||
|
||||
uint32 nslots = fun->countInterpretedReservedSlots();
|
||||
if (!nslots)
|
||||
return closure;
|
||||
if (!js_EnsureReservedSlots(cx, closure, nslots))
|
||||
return NULL;
|
||||
|
||||
}
|
||||
return closure;
|
||||
}
|
||||
|
||||
|
|
|
@ -315,7 +315,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
#endif
|
||||
|
||||
if (scopeIndex != 0 || protoIndex != 1) {
|
||||
khash = PROPERTY_CACHE_HASH_ATOM(atom, obj, pobj);
|
||||
khash = PROPERTY_CACHE_HASH_ATOM(atom, obj);
|
||||
PCMETER(if (PCVCAP_TAG(cache->table[khash].vcap) <= 1)
|
||||
cache->pcrecycles++);
|
||||
pc = (jsbytecode *) atom;
|
||||
|
@ -381,7 +381,7 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
|
|||
|
||||
obj = *objp;
|
||||
JS_ASSERT(OBJ_IS_NATIVE(obj));
|
||||
entry = &JS_PROPERTY_CACHE(cx).table[PROPERTY_CACHE_HASH_ATOM(atom, obj, NULL)];
|
||||
entry = &JS_PROPERTY_CACHE(cx).table[PROPERTY_CACHE_HASH_ATOM(atom, obj)];
|
||||
*entryp = entry;
|
||||
vcap = entry->vcap;
|
||||
|
||||
|
@ -441,7 +441,7 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
|
|||
|
||||
id = js_CheckForStringIndex(id);
|
||||
JS_ASSERT(OBJ_SCOPE(pobj)->lookup(id));
|
||||
JS_ASSERT(OBJ_SCOPE(pobj)->object == pobj);
|
||||
JS_ASSERT_IF(OBJ_SCOPE(pobj)->object, OBJ_SCOPE(pobj)->object == pobj);
|
||||
#endif
|
||||
*pobjp = pobj;
|
||||
return NULL;
|
||||
|
@ -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]);
|
||||
|
@ -4643,7 +4650,7 @@ js_Interpret(JSContext *cx)
|
|||
uint32 kshape = OBJ_SHAPE(obj);
|
||||
|
||||
/*
|
||||
* Open-code JS_PROPERTY_CACHE_TEST, specializing for two
|
||||
* Open-code PROPERTY_CACHE_TEST, specializing for two
|
||||
* important set-property cases. First:
|
||||
*
|
||||
* function f(a, b, c) {
|
||||
|
|
|
@ -193,9 +193,8 @@ typedef struct JSInlineFrame {
|
|||
|
||||
/*
|
||||
* Property cache with structurally typed capabilities for invalidation, for
|
||||
* polymorphic callsite method/get/set speedups.
|
||||
*
|
||||
* See bug https://bugzilla.mozilla.org/show_bug.cgi?id=365851.
|
||||
* polymorphic callsite method/get/set speedups. For details, see
|
||||
* <https://developer.mozilla.org/en/SpiderMonkey/Internals/Property_cache>.
|
||||
*/
|
||||
#define PROPERTY_CACHE_LOG2 12
|
||||
#define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2)
|
||||
|
@ -213,7 +212,7 @@ typedef struct JSInlineFrame {
|
|||
#define PROPERTY_CACHE_HASH_PC(pc,kshape) \
|
||||
PROPERTY_CACHE_HASH(pc, kshape)
|
||||
|
||||
#define PROPERTY_CACHE_HASH_ATOM(atom,obj,pobj) \
|
||||
#define PROPERTY_CACHE_HASH_ATOM(atom,obj) \
|
||||
PROPERTY_CACHE_HASH((jsuword)(atom) >> 2, OBJ_SHAPE(obj))
|
||||
|
||||
/*
|
||||
|
|
|
@ -2734,7 +2734,7 @@ js_NewString(JSContext *cx, jschar *chars, size_t length)
|
|||
if (JS_ON_TRACE(cx)) {
|
||||
/*
|
||||
* If we can't leave the trace, signal OOM condition, otherwise
|
||||
* exit from trace and proceed with GC.
|
||||
* exit from trace before throwing.
|
||||
*/
|
||||
if (!js_CanLeaveTrace(cx))
|
||||
return NULL;
|
||||
|
|
|
@ -1141,7 +1141,7 @@ public:
|
|||
{
|
||||
// if the return type is ARGSIZE_F, we have
|
||||
// to do a quadCall(qjoin(call,callh))
|
||||
if ((ci->_argtypes & 3) == ARGSIZE_F)
|
||||
if ((ci->_argtypes & ARGSIZE_MASK_ANY) == ARGSIZE_F)
|
||||
return quadCall(ci, args);
|
||||
|
||||
return out->insCall(ci, args);
|
||||
|
@ -3694,7 +3694,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) {
|
||||
|
@ -5386,7 +5386,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);
|
||||
|
@ -5484,7 +5484,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);
|
||||
|
@ -5498,6 +5498,7 @@ ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount,
|
|||
|
||||
cx->interpState = state->prev;
|
||||
|
||||
JS_ASSERT(!cx->bailExit);
|
||||
JS_ASSERT(lr->exitType != LOOP_EXIT || !lr->calldepth);
|
||||
tm->tracecx = NULL;
|
||||
LeaveTree(*state, lr);
|
||||
|
@ -5796,7 +5797,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);
|
||||
|
@ -6754,15 +6755,12 @@ JS_DEFINE_CALLINFO_6(extern, UINT32, GetClosureArg, CONTEXT, OBJECT, UINT32,
|
|||
* generate LIR to access the given property. Return JSRS_CONTINUE on success,
|
||||
* otherwise abort and return JSRS_STOP. There are 3 outparams:
|
||||
*
|
||||
* vp the address of the current property value
|
||||
* ins LIR instruction representing the property value on trace
|
||||
* tracked true iff the property value is tracked on this trace. If true,
|
||||
* then the tracked value can be modified using the tracker set
|
||||
* functions. If false, then the value comes from a call to a
|
||||
* builtin to access an upvar, and can't be modified directly.
|
||||
* vp the address of the current property value
|
||||
* ins LIR instruction representing the property value on trace
|
||||
* NameResult describes how to look up name; see comment for NameResult in jstracer.h
|
||||
*/
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, bool& tracked)
|
||||
TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, NameResult& nr)
|
||||
{
|
||||
JS_ASSERT(obj != globalObj);
|
||||
|
||||
|
@ -6792,7 +6790,7 @@ TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, bool& track
|
|||
vp = &STOBJ_GET_SLOT(obj, sprop->slot);
|
||||
ins = get(vp);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||
tracked = true;
|
||||
nr.tracked = true;
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -6829,7 +6827,7 @@ TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, bool& track
|
|||
// At this point we are guaranteed to be looking at an active call object
|
||||
// whose properties are stored in the corresponding JSStackFrame.
|
||||
ins = get(vp);
|
||||
tracked = true;
|
||||
nr.tracked = true;
|
||||
return JSRS_CONTINUE;
|
||||
} else {
|
||||
// Compute number of scope chain links to result.
|
||||
|
@ -6864,7 +6862,10 @@ TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, bool& track
|
|||
"guard(type-stable name access)"),
|
||||
BRANCH_EXIT);
|
||||
ins = stackLoad(outp, type);
|
||||
tracked = false;
|
||||
nr.tracked = false;
|
||||
nr.obj = obj;
|
||||
nr.scopeIndex = scopeIndex;
|
||||
nr.sprop = sprop;
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
@ -7153,24 +7154,26 @@ TraceRecorder::ifop()
|
|||
* "first" time we hit the op. Later, when we start traces after exiting that
|
||||
* trace, we just patch.
|
||||
*/
|
||||
JS_REQUIRES_STACK LIns*
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::tableswitch()
|
||||
{
|
||||
jsval& v = stackval(-1);
|
||||
|
||||
/* No need to guard if the condition can't match any of the cases. */
|
||||
if (!isNumber(v))
|
||||
return NULL;
|
||||
return JSRS_CONTINUE;
|
||||
|
||||
/* No need to guard if the condition is constant. */
|
||||
LIns* v_ins = f2i(get(&v));
|
||||
if (v_ins->isconst() || v_ins->isconstq())
|
||||
return NULL;
|
||||
return JSRS_CONTINUE;
|
||||
|
||||
jsbytecode* pc = cx->fp->regs->pc;
|
||||
/* Starting a new trace after exiting a trace via switch. */
|
||||
if (anchor &&
|
||||
(anchor->exitType == CASE_EXIT || anchor->exitType == DEFAULT_EXIT) &&
|
||||
fragment->ip == pc) {
|
||||
return NULL;
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
/* Decode jsop. */
|
||||
|
@ -7191,14 +7194,8 @@ TraceRecorder::tableswitch()
|
|||
* Really large tables won't fit in a page. This is a conservative check.
|
||||
* If it matters in practice we need to go off-page.
|
||||
*/
|
||||
if ((high + 1 - low) * sizeof(intptr_t*) + 128 > (unsigned) LARGEST_UNDERRUN_PROT) {
|
||||
/*
|
||||
* This throws away the return value of switchop but it seems ok
|
||||
* because switchop always returns true.
|
||||
*/
|
||||
(void) switchop();
|
||||
return NULL;
|
||||
}
|
||||
if ((high + 1 - low) * sizeof(intptr_t*) + 128 > (unsigned) LARGEST_UNDERRUN_PROT)
|
||||
return switchop();
|
||||
|
||||
/* Generate switch LIR. */
|
||||
LIns* si_ins = lir_buf_writer->insSkip(sizeof(SwitchInfo));
|
||||
|
@ -7212,7 +7209,10 @@ TraceRecorder::tableswitch()
|
|||
lir->insStorei(diff, lir->insImmPtr(&si->index), 0);
|
||||
VMSideExit* exit = snapshot(CASE_EXIT);
|
||||
exit->switchInfo = si;
|
||||
return lir->insGuard(LIR_xtbl, diff, createGuardRecord(exit));
|
||||
LIns* guardIns = lir->insGuard(LIR_xtbl, diff, createGuardRecord(exit));
|
||||
fragment->lastIns = guardIns;
|
||||
compile(&JS_TRACE_MONITOR(cx));
|
||||
return JSRS_STOP;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -9005,7 +9005,11 @@ TraceRecorder::emitNativePropertyOp(JSScope* scope, JSScopeProperty* sprop, LIns
|
|||
|
||||
CallInfo* ci = (CallInfo*) lir->insSkip(sizeof(struct CallInfo))->payload();
|
||||
ci->_address = uintptr_t(setflag ? sprop->setter : sprop->getter);
|
||||
ci->_argtypes = ARGSIZE_LO | ARGSIZE_LO << 2 | ARGSIZE_LO << 4 | ARGSIZE_LO << 6 | ARGSIZE_LO << 8;
|
||||
ci->_argtypes = ARGSIZE_LO << (0*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (1*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (2*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (3*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (4*ARGSIZE_SHIFT);
|
||||
ci->_cse = ci->_fold = 0;
|
||||
ci->_abi = ABI_CDECL;
|
||||
#ifdef DEBUG
|
||||
|
@ -9014,8 +9018,10 @@ TraceRecorder::emitNativePropertyOp(JSScope* scope, JSScopeProperty* sprop, LIns
|
|||
LIns* args[] = { vp_ins, INS_CONSTWORD(SPROP_USERID(sprop)), obj_ins, cx_ins };
|
||||
LIns* ok_ins = lir->insCall(ci, args);
|
||||
|
||||
// Unroot the vp.
|
||||
lir->insStorei(INS_CONSTPTR(NULL), cx_ins, offsetof(JSContext, nativeVp));
|
||||
// Cleanup.
|
||||
LIns* null_ins = INS_CONSTPTR(NULL);
|
||||
lir->insStorei(null_ins, cx_ins, offsetof(JSContext, nativeVp));
|
||||
lir->insStorei(null_ins, cx_ins, offsetof(JSContext, bailExit));
|
||||
|
||||
// Guard that the call succeeded and builtinStatus is still 0.
|
||||
// If the native op succeeds but we deep-bail here, the result value is
|
||||
|
@ -9318,7 +9324,10 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
|
|||
args[0] = invokevp_ins;
|
||||
args[1] = lir->insImm(argc);
|
||||
args[2] = cx_ins;
|
||||
types = ARGSIZE_LO | ARGSIZE_LO << 2 | ARGSIZE_LO << 4 | ARGSIZE_LO << 6;
|
||||
types = ARGSIZE_LO << (0*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (1*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (2*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (3*ARGSIZE_SHIFT);
|
||||
} else {
|
||||
native_rval_ins = lir->ins2i(LIR_piadd, invokevp_ins, int32_t((vplen - 1) * sizeof(jsval)));
|
||||
args[0] = native_rval_ins;
|
||||
|
@ -9326,8 +9335,12 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
|
|||
args[2] = lir->insImm(argc);
|
||||
args[3] = this_ins;
|
||||
args[4] = cx_ins;
|
||||
types = ARGSIZE_LO | ARGSIZE_LO << 2 | ARGSIZE_LO << 4 | ARGSIZE_LO << 6 |
|
||||
ARGSIZE_LO << 8 | ARGSIZE_LO << 10;
|
||||
types = ARGSIZE_LO << (0*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (1*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (2*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (3*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (4*ARGSIZE_SHIFT) |
|
||||
ARGSIZE_LO << (5*ARGSIZE_SHIFT);
|
||||
}
|
||||
|
||||
// Generate CallInfo and a JSTraceableNative structure on the fly. Do not
|
||||
|
@ -9526,13 +9539,20 @@ TraceRecorder::incName(jsint incr, bool pre)
|
|||
{
|
||||
jsval* vp;
|
||||
LIns* v_ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(name(vp, v_ins, tracked));
|
||||
if (!tracked)
|
||||
ABORT_TRACE("incName on non-tracked value not supported");
|
||||
NameResult nr;
|
||||
CHECK_STATUS(name(vp, v_ins, nr));
|
||||
CHECK_STATUS(inc(*vp, v_ins, incr, pre));
|
||||
set(vp, v_ins);
|
||||
return JSRS_CONTINUE;
|
||||
if (nr.tracked) {
|
||||
set(vp, v_ins);
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
if (OBJ_GET_CLASS(cx, nr.obj) != &js_CallClass)
|
||||
ABORT_TRACE("incName on unsupported object class");
|
||||
LIns* callobj_ins = get(&cx->fp->argv[-2]);
|
||||
for (jsint i = 0; i < nr.scopeIndex; ++i)
|
||||
callobj_ins = stobj_get_parent(callobj_ins);
|
||||
return setCallProp(callobj_ins, nr.sprop, v_ins, *vp);
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
|
@ -9665,9 +9685,11 @@ TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop
|
|||
if (sprop->attrs & JSPROP_SETTER)
|
||||
ABORT_TRACE("can't trace JavaScript function setter");
|
||||
|
||||
// These two cases are actually errors and can't be cached.
|
||||
JS_ASSERT(!(sprop->attrs & JSPROP_GETTER)); // getter without setter
|
||||
JS_ASSERT(!(sprop->attrs & JSPROP_READONLY));
|
||||
// These two cases are errors and can't be traced.
|
||||
if (sprop->attrs & JSPROP_GETTER)
|
||||
ABORT_TRACE("can't assign to property with script getter but no setter");
|
||||
if (sprop->attrs & JSPROP_READONLY)
|
||||
ABORT_TRACE("can't assign to readonly property");
|
||||
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(l));
|
||||
JSObject* obj = JSVAL_TO_OBJECT(l);
|
||||
|
@ -9678,25 +9700,8 @@ TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop
|
|||
|
||||
// Fast path for CallClass. This is about 20% faster than the general case.
|
||||
if (OBJ_GET_CLASS(cx, obj) == &js_CallClass) {
|
||||
const CallInfo* ci = NULL;
|
||||
if (sprop->setter == SetCallArg)
|
||||
ci = &js_SetCallArg_ci;
|
||||
else if (sprop->setter == SetCallVar)
|
||||
ci = &js_SetCallVar_ci;
|
||||
else
|
||||
ABORT_TRACE("can't trace special CallClass setter");
|
||||
|
||||
LIns* v_ins = get(&v);
|
||||
box_jsval(v, v_ins);
|
||||
LIns* args[] = {
|
||||
v_ins,
|
||||
INS_CONST(SPROP_USERID(sprop)),
|
||||
obj_ins,
|
||||
cx_ins
|
||||
};
|
||||
LIns* call_ins = lir->insCall(ci, args);
|
||||
guard(false, addName(lir->ins_eq0(call_ins), "guard(set upvar)"), STATUS_EXIT);
|
||||
return JSRS_CONTINUE;
|
||||
v_ins = get(&v);
|
||||
return setCallProp(obj_ins, sprop, v_ins, v);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -9741,6 +9746,29 @@ TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop
|
|||
return nativeSet(obj, obj_ins, sprop, v, v_ins);
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::setCallProp(LIns *callobj_ins, JSScopeProperty *sprop, LIns *v_ins, jsval v)
|
||||
{
|
||||
const CallInfo* ci = NULL;
|
||||
if (sprop->setter == SetCallArg)
|
||||
ci = &js_SetCallArg_ci;
|
||||
else if (sprop->setter == SetCallVar)
|
||||
ci = &js_SetCallVar_ci;
|
||||
else
|
||||
ABORT_TRACE("can't trace special CallClass setter");
|
||||
|
||||
box_jsval(v, v_ins);
|
||||
LIns* args[] = {
|
||||
v_ins,
|
||||
INS_CONST(SPROP_USERID(sprop)),
|
||||
callobj_ins,
|
||||
cx_ins
|
||||
};
|
||||
LIns* call_ins = lir->insCall(ci, args);
|
||||
guard(false, addName(lir->ins_eq0(call_ins), "guard(set upvar)"), STATUS_EXIT);
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop)
|
||||
{
|
||||
|
@ -10122,8 +10150,8 @@ TraceRecorder::record_JSOP_CALLNAME()
|
|||
if (obj != globalObj) {
|
||||
jsval* vp;
|
||||
LIns* ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(scopeChainProp(obj, vp, ins, tracked));
|
||||
NameResult nr;
|
||||
CHECK_STATUS(scopeChainProp(obj, vp, ins, nr));
|
||||
stack(0, ins);
|
||||
stack(1, INS_CONSTPTR(globalObj));
|
||||
return JSRS_CONTINUE;
|
||||
|
@ -10357,7 +10385,7 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
|
|||
if (callDepth >= treeInfo->maxCallDepth)
|
||||
treeInfo->maxCallDepth = callDepth + 1;
|
||||
if (callDepth == 0)
|
||||
fi->spoffset = 2 /*callee,this*/ + argc - fi->spdist;
|
||||
fi->spoffset = -fp->script->nfixed;
|
||||
|
||||
lir->insStorei(INS_CONSTPTR(fi), lirbuf->rp, callDepth * sizeof(FrameInfo*));
|
||||
|
||||
|
@ -10579,7 +10607,7 @@ TraceRecorder::record_NativeCallComplete()
|
|||
} else {
|
||||
/* Convert the result to double if the builtin returns int32. */
|
||||
if (JSVAL_IS_NUMBER(v) &&
|
||||
(pendingTraceableNative->builtin->_argtypes & 3) == nanojit::ARGSIZE_LO) {
|
||||
(pendingTraceableNative->builtin->_argtypes & ARGSIZE_MASK_ANY) == ARGSIZE_LO) {
|
||||
set(&v, lir->ins1(LIR_i2f, v_ins));
|
||||
}
|
||||
}
|
||||
|
@ -10590,11 +10618,11 @@ TraceRecorder::record_NativeCallComplete()
|
|||
}
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::name(jsval*& vp, LIns*& ins, bool& tracked)
|
||||
TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr)
|
||||
{
|
||||
JSObject* obj = cx->fp->scopeChain;
|
||||
if (obj != globalObj)
|
||||
return scopeChainProp(obj, vp, ins, tracked);
|
||||
return scopeChainProp(obj, vp, ins, nr);
|
||||
|
||||
/* Can't use prop here, because we don't want unboxing from global slots. */
|
||||
LIns* obj_ins = scopeChain();
|
||||
|
@ -10634,7 +10662,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, bool& tracked)
|
|||
|
||||
vp = &STOBJ_GET_SLOT(obj, slot);
|
||||
ins = get(vp);
|
||||
tracked = true;
|
||||
nr.tracked = true;
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -10904,8 +10932,8 @@ TraceRecorder::record_JSOP_NAME()
|
|||
{
|
||||
jsval* vp;
|
||||
LIns* v_ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(name(vp, v_ins, tracked));
|
||||
NameResult nr;
|
||||
CHECK_STATUS(name(vp, v_ins, nr));
|
||||
stack(0, v_ins);
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
@ -10988,12 +11016,7 @@ TraceRecorder::record_JSOP_TABLESWITCH()
|
|||
{
|
||||
#ifdef NANOJIT_IA32
|
||||
/* Handle tableswitches specially -- prepare a jump table if needed. */
|
||||
LIns* guardIns = tableswitch();
|
||||
if (guardIns) {
|
||||
fragment->lastIns = guardIns;
|
||||
compile(&JS_TRACE_MONITOR(cx));
|
||||
}
|
||||
return JSRS_STOP;
|
||||
return tableswitch();
|
||||
#else
|
||||
return switchop();
|
||||
#endif
|
||||
|
@ -11239,9 +11262,9 @@ TraceRecorder::record_JSOP_FORNAME()
|
|||
{
|
||||
jsval* vp;
|
||||
LIns* x_ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(name(vp, x_ins, tracked));
|
||||
if (!tracked)
|
||||
NameResult nr;
|
||||
CHECK_STATUS(name(vp, x_ins, nr));
|
||||
if (!nr.tracked)
|
||||
ABORT_TRACE("forname on non-tracked value not supported");
|
||||
set(vp, stack(-1));
|
||||
return JSRS_CONTINUE;
|
||||
|
@ -11310,14 +11333,19 @@ TraceRecorder::record_JSOP_BINDNAME()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If obj is a js_CallClass object, then we are tracing a reference to an
|
||||
* upvar in a heavyweight function. We cannot reach this point of the trace
|
||||
* with a different call object because of the guard on the function call,
|
||||
* so we can assume the result of the bindname is constant on this trace.
|
||||
*/
|
||||
if (obj != globalObj && OBJ_GET_CLASS(cx, obj) != &js_CallClass)
|
||||
ABORT_TRACE("Can only trace JSOP_BINDNAME with global or call object");
|
||||
if (obj != globalObj) {
|
||||
if (OBJ_GET_CLASS(cx, obj) != &js_CallClass)
|
||||
ABORT_TRACE("Can only trace JSOP_BINDNAME with global or call object");
|
||||
|
||||
/*
|
||||
* The interpreter version of JSOP_BINDNAME does the full lookup. We
|
||||
* don't need to do that on trace because we will leave trace if the
|
||||
* scope ever changes, so the result of the lookup cannot change.
|
||||
*/
|
||||
JS_ASSERT(obj == cx->fp->scopeChain || obj == OBJ_GET_PARENT(cx, cx->fp->scopeChain));
|
||||
stack(0, stobj_get_parent(get(&cx->fp->argv[-2])));
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The trace is specialized to this global object. Furthermore, we know it
|
||||
|
@ -12207,8 +12235,8 @@ TraceRecorder::record_JSOP_GETXPROP()
|
|||
|
||||
jsval* vp;
|
||||
LIns* v_ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(name(vp, v_ins, tracked));
|
||||
NameResult nr;
|
||||
CHECK_STATUS(name(vp, v_ins, nr));
|
||||
stack(-1, v_ins);
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
@ -12647,6 +12675,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")
|
||||
|
|
|
@ -627,9 +627,19 @@ class TraceRecorder : public avmplus::GCObject {
|
|||
JS_REQUIRES_STACK jsval& varval(unsigned n) const;
|
||||
JS_REQUIRES_STACK jsval& stackval(int n) const;
|
||||
|
||||
struct NameResult {
|
||||
// |tracked| is true iff the result of the name lookup is a variable that
|
||||
// is already in the tracker. The rest of the fields are set only if
|
||||
// |tracked| is false.
|
||||
bool tracked;
|
||||
JSObject *obj; // Call object where name was found
|
||||
jsint scopeIndex; // scope chain links from callee to obj
|
||||
JSScopeProperty *sprop; // sprop name was resolved to
|
||||
};
|
||||
|
||||
JS_REQUIRES_STACK nanojit::LIns* scopeChain() const;
|
||||
JS_REQUIRES_STACK JSStackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
|
||||
JS_REQUIRES_STACK JSRecordingStatus scopeChainProp(JSObject* obj, jsval*& vp, nanojit::LIns*& ins, bool& tracked);
|
||||
JS_REQUIRES_STACK JSRecordingStatus scopeChainProp(JSObject* obj, jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
|
||||
|
||||
JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n);
|
||||
JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i);
|
||||
|
@ -651,7 +661,7 @@ class TraceRecorder : public avmplus::GCObject {
|
|||
JS_REQUIRES_STACK JSRecordingStatus ifop();
|
||||
JS_REQUIRES_STACK JSRecordingStatus switchop();
|
||||
#ifdef NANOJIT_IA32
|
||||
JS_REQUIRES_STACK nanojit::LIns* tableswitch();
|
||||
JS_REQUIRES_STACK JSRecordingStatus tableswitch();
|
||||
#endif
|
||||
JS_REQUIRES_STACK JSRecordingStatus inc(jsval& v, jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK JSRecordingStatus inc(jsval& v, nanojit::LIns*& v_ins, jsint incr,
|
||||
|
@ -702,18 +712,24 @@ class TraceRecorder : public avmplus::GCObject {
|
|||
nanojit::LIns*& dslots_ins);
|
||||
nanojit::LIns* stobj_get_slot(nanojit::LIns* obj_ins, unsigned slot,
|
||||
nanojit::LIns*& dslots_ins);
|
||||
|
||||
nanojit::LIns* stobj_get_private(nanojit::LIns* obj_ins, jsval mask=JSVAL_INT) {
|
||||
return lir->ins2(nanojit::LIR_piand,
|
||||
stobj_get_fslot(obj_ins, JSSLOT_PRIVATE),
|
||||
lir->insImmPtr((void*) ~mask));
|
||||
}
|
||||
|
||||
nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins) {
|
||||
return stobj_get_fslot(obj_ins, JSSLOT_PARENT);
|
||||
}
|
||||
|
||||
JSRecordingStatus native_get(nanojit::LIns* obj_ins, nanojit::LIns* pobj_ins,
|
||||
JSScopeProperty* sprop, nanojit::LIns*& dslots_ins,
|
||||
nanojit::LIns*& v_ins);
|
||||
|
||||
nanojit::LIns* getStringLength(nanojit::LIns* str_ins);
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus name(jsval*& vp, nanojit::LIns*& ins, bool& tracked);
|
||||
JS_REQUIRES_STACK JSRecordingStatus name(jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
|
||||
JS_REQUIRES_STACK JSRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot,
|
||||
nanojit::LIns*& v_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus denseArrayElement(jsval& oval, jsval& idx, jsval*& vp,
|
||||
|
@ -729,6 +745,9 @@ class TraceRecorder : public avmplus::GCObject {
|
|||
JS_REQUIRES_STACK JSRecordingStatus setProp(jsval &l, JSPropCacheEntry* entry,
|
||||
JSScopeProperty* sprop,
|
||||
jsval &v, nanojit::LIns*& v_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus setCallProp(nanojit::LIns *callobj_ins,
|
||||
JSScopeProperty *sprop, nanojit::LIns *v_ins,
|
||||
jsval v);
|
||||
|
||||
JS_REQUIRES_STACK void box_jsval(jsval v, nanojit::LIns*& v_ins);
|
||||
JS_REQUIRES_STACK void unbox_jsval(jsval v, nanojit::LIns*& v_ins, VMSideExit* exit);
|
||||
|
@ -972,14 +991,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;
|
||||
|
@ -987,30 +1010,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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -568,7 +568,7 @@ FragmentAssembler::assemble_call(const string &op)
|
|||
for (size_t i = 0; i < mTokens.size(); ++i) {
|
||||
args[i] = ref(mTokens[mTokens.size() - (i+1)]);
|
||||
ci->_argtypes |= args[i]->isQuad() ? ARGSIZE_F : ARGSIZE_LO;
|
||||
ci->_argtypes <<= 2;
|
||||
ci->_argtypes <<= ARGSIZE_SHIFT;
|
||||
}
|
||||
|
||||
// Select return type from opcode.
|
||||
|
|
|
@ -2018,7 +2018,7 @@ namespace nanojit
|
|||
uint32_t argc = 0;
|
||||
uint32_t argt = _argtypes;
|
||||
for (uint32_t i = 0; i < MAXARGS; ++i) {
|
||||
argt >>= 2;
|
||||
argt >>= ARGSIZE_SHIFT;
|
||||
if (!argt)
|
||||
break;
|
||||
argc += (argt & mask) != 0;
|
||||
|
@ -2031,8 +2031,8 @@ namespace nanojit
|
|||
uint32_t argt = _argtypes;
|
||||
uint32_t argc = 0;
|
||||
for (uint32_t i = 0; i < MAXARGS; i++) {
|
||||
argt >>= 2;
|
||||
ArgSize a = ArgSize(argt&3);
|
||||
argt >>= ARGSIZE_SHIFT;
|
||||
ArgSize a = ArgSize(argt & ARGSIZE_MASK_ANY);
|
||||
if (a != ARGSIZE_NONE) {
|
||||
sizes[argc++] = a;
|
||||
} else {
|
||||
|
|
|
@ -1004,10 +1004,13 @@ namespace nanojit
|
|||
|
||||
LIns* LirBufWriter::insCall(const CallInfo *ci, LInsp args[])
|
||||
{
|
||||
static const LOpcode k_callmap[] = { LIR_call, LIR_fcall, LIR_call, LIR_callh };
|
||||
static const LOpcode k_callmap[] = {
|
||||
// ARGSIZE_NONE ARGSIZE_F ARGSIZE_LO ARGSIZE_Q (4) (5) ARGSIZE_U (7)
|
||||
LIR_call, LIR_fcall, LIR_call, LIR_callh, LIR_skip, LIR_skip, LIR_call, LIR_skip
|
||||
};
|
||||
|
||||
uint32_t argt = ci->_argtypes;
|
||||
LOpcode op = k_callmap[argt & 3];
|
||||
LOpcode op = k_callmap[argt & ARGSIZE_MASK_ANY];
|
||||
NanoAssert(op != LIR_skip); // LIR_skip here is just an error condition
|
||||
|
||||
ArgSize sizes[MAXARGS];
|
||||
|
@ -1757,8 +1760,13 @@ namespace nanojit
|
|||
#endif
|
||||
case LIR_fcall:
|
||||
case LIR_call: {
|
||||
sprintf(s, "%s = %s ( ", formatRef(i), i->callInfo()->_name);
|
||||
for (int32_t j=i->argc()-1; j >= 0; j--) {
|
||||
const CallInfo* call = i->callInfo();
|
||||
int32_t argc = i->argc();
|
||||
if (call->isIndirect())
|
||||
sprintf(s, "%s = %s [%s] ( ", formatRef(i), lirNames[op], formatRef(i->arg(--argc)));
|
||||
else
|
||||
sprintf(s, "%s = %s #%s ( ", formatRef(i), lirNames[op], call->_name);
|
||||
for (int32_t j = argc - 1; j >= 0; j--) {
|
||||
s += strlen(s);
|
||||
sprintf(s, "%s ",formatRef(i->arg(j)));
|
||||
}
|
||||
|
|
|
@ -71,6 +71,12 @@ namespace nanojit
|
|||
#undef OPDEF64
|
||||
};
|
||||
|
||||
#ifdef NANOJIT_64BIT
|
||||
# define PTR_SIZE(a,b) b
|
||||
#else
|
||||
# define PTR_SIZE(a,b) a
|
||||
#endif
|
||||
|
||||
#if defined NANOJIT_64BIT
|
||||
#define LIR_ldp LIR_ldq
|
||||
#define LIR_piadd LIR_qiadd
|
||||
|
@ -100,30 +106,45 @@ namespace nanojit
|
|||
|
||||
enum ArgSize {
|
||||
ARGSIZE_NONE = 0,
|
||||
ARGSIZE_F = 1,
|
||||
ARGSIZE_LO = 2,
|
||||
ARGSIZE_Q = 3,
|
||||
_ARGSIZE_MASK_INT = 2,
|
||||
_ARGSIZE_MASK_ANY = 3
|
||||
ARGSIZE_F = 1, // double (64bit)
|
||||
ARGSIZE_I = 2, // int32_t
|
||||
ARGSIZE_Q = 3, // uint64_t
|
||||
ARGSIZE_U = 6, // uint32_t
|
||||
ARGSIZE_MASK_ANY = 7,
|
||||
ARGSIZE_MASK_INT = 2,
|
||||
ARGSIZE_SHIFT = 3,
|
||||
|
||||
// aliases
|
||||
ARGSIZE_P = PTR_SIZE(ARGSIZE_I, ARGSIZE_Q), // pointer
|
||||
ARGSIZE_LO = ARGSIZE_I, // int32_t
|
||||
ARGSIZE_B = ARGSIZE_I, // bool
|
||||
ARGSIZE_V = ARGSIZE_NONE // void
|
||||
};
|
||||
|
||||
enum IndirectCall {
|
||||
CALL_INDIRECT = 0
|
||||
};
|
||||
|
||||
struct CallInfo
|
||||
{
|
||||
uintptr_t _address;
|
||||
uint32_t _argtypes:18; // 9 2-bit fields indicating arg type, by ARGSIZE above (including ret type): a1 a2 a3 a4 a5 ret
|
||||
uint8_t _cse:1; // true if no side effects
|
||||
uint8_t _fold:1; // true if no side effects
|
||||
uintptr_t _address;
|
||||
uint32_t _argtypes:27; // 9 3-bit fields indicating arg type, by ARGSIZE above (including ret type): a1 a2 a3 a4 a5 ret
|
||||
uint8_t _cse:1; // true if no side effects
|
||||
uint8_t _fold:1; // true if no side effects
|
||||
AbiKind _abi:3;
|
||||
verbose_only ( const char* _name; )
|
||||
|
||||
uint32_t FASTCALL _count_args(uint32_t mask) const;
|
||||
uint32_t get_sizes(ArgSize*) const;
|
||||
|
||||
inline bool isIndirect() const {
|
||||
return _address < 256;
|
||||
}
|
||||
inline uint32_t FASTCALL count_args() const {
|
||||
return _count_args(_ARGSIZE_MASK_ANY);
|
||||
return _count_args(ARGSIZE_MASK_ANY);
|
||||
}
|
||||
inline uint32_t FASTCALL count_iargs() const {
|
||||
return _count_args(_ARGSIZE_MASK_INT);
|
||||
return _count_args(ARGSIZE_MASK_INT);
|
||||
}
|
||||
// fargs = args - iargs
|
||||
};
|
||||
|
|
|
@ -752,9 +752,9 @@ Assembler::asm_call(LInsp ins)
|
|||
uint32_t atypes = call->_argtypes;
|
||||
|
||||
// skip return type
|
||||
ArgSize rsize = (ArgSize)(atypes & 3);
|
||||
ArgSize rsize = (ArgSize)(atypes & ARGSIZE_MASK_ANY);
|
||||
|
||||
atypes >>= 2;
|
||||
atypes >>= ARGSIZE_SHIFT;
|
||||
|
||||
// if we're using VFP, and the return type is a double,
|
||||
// it'll come back in R0/R1. We need to either place it
|
||||
|
|
|
@ -151,7 +151,7 @@ namespace nanojit
|
|||
underrunProtect(8);
|
||||
NOP();
|
||||
|
||||
ArgSize sizes[10];
|
||||
ArgSize sizes[MAXARGS];
|
||||
uint32_t argc = call->get_sizes(sizes);
|
||||
|
||||
NanoAssert(ins->isop(LIR_call) || ins->isop(LIR_fcall));
|
||||
|
|
|
@ -175,6 +175,12 @@ namespace nanojit
|
|||
uint32_t iargs = call->count_iargs();
|
||||
int32_t fargs = call->count_args() - iargs;
|
||||
|
||||
bool indirect = call->isIndirect();
|
||||
if (indirect) {
|
||||
// target arg isn't pushed, its consumed in the call
|
||||
iargs --;
|
||||
}
|
||||
|
||||
uint32_t max_regs = max_abi_regs[call->_abi];
|
||||
if (max_regs > iargs)
|
||||
max_regs = iargs;
|
||||
|
@ -204,7 +210,16 @@ namespace nanojit
|
|||
}
|
||||
|
||||
NanoAssert(ins->isop(LIR_call) || ins->isop(LIR_fcall));
|
||||
CALL(call);
|
||||
if (!indirect) {
|
||||
CALL(call);
|
||||
}
|
||||
else {
|
||||
// indirect call. x86 Calling conventions don't use EAX as an
|
||||
// argument, and do use EAX as a return value. We need a register
|
||||
// for the address to call, so we use EAX since it will always be
|
||||
// available
|
||||
CALLr(call, EAX);
|
||||
}
|
||||
|
||||
// make sure fpu stack is empty before call (restoreCallerSaved)
|
||||
NanoAssert(_allocator.isFree(FST0));
|
||||
|
@ -213,8 +228,12 @@ namespace nanojit
|
|||
// pre-assign registers to the first N 4B args based on the calling convention
|
||||
uint32_t n = 0;
|
||||
|
||||
ArgSize sizes[2*MAXARGS];
|
||||
ArgSize sizes[MAXARGS];
|
||||
uint32_t argc = call->get_sizes(sizes);
|
||||
if (indirect) {
|
||||
argc--;
|
||||
asm_arg(ARGSIZE_P, ins->arg(argc), EAX);
|
||||
}
|
||||
|
||||
for(uint32_t i=0; i < argc; i++)
|
||||
{
|
||||
|
@ -1283,7 +1302,7 @@ namespace nanojit
|
|||
NanoAssert(0); // not supported
|
||||
}
|
||||
}
|
||||
else if (sz == ARGSIZE_LO)
|
||||
else if (sz == ARGSIZE_I || sz == ARGSIZE_U)
|
||||
{
|
||||
if (r != UnknownReg) {
|
||||
// arg goes in specific register
|
||||
|
|
|
@ -840,7 +840,7 @@ namespace nanojit
|
|||
IMM32( (uint32_t)offset ); \
|
||||
*(--_nIns) = 0xE8; \
|
||||
verbose_only(asm_output("call %s",(c->_name));) \
|
||||
debug_only(if ((c->_argtypes&3)==ARGSIZE_F) fpu_push();)\
|
||||
debug_only(if ((c->_argtypes & ARGSIZE_MASK_ANY)==ARGSIZE_F) fpu_push();)\
|
||||
} while (0)
|
||||
|
||||
// indirect call thru register
|
||||
|
@ -849,7 +849,7 @@ namespace nanojit
|
|||
underrunProtect(2);\
|
||||
ALU(0xff, 2, (r));\
|
||||
verbose_only(asm_output("call %s",gpn(r));) \
|
||||
debug_only(if ((c->_argtypes&3)==ARGSIZE_F) fpu_push();)\
|
||||
debug_only(if ((c->_argtypes & ARGSIZE_MASK_ANY)==ARGSIZE_F) fpu_push();)\
|
||||
} while (0)
|
||||
|
||||
|
||||
|
|
|
@ -4365,6 +4365,49 @@ function testSwitchUndefined()
|
|||
testSwitchUndefined.expected = 5;
|
||||
test(testSwitchUndefined);
|
||||
|
||||
function testTableSwitch1() {
|
||||
var x = 'miss';
|
||||
var i, j = 0;
|
||||
for (i = 0; i < RUNLOOP + 10; i++) {
|
||||
switch (x) {
|
||||
case 1: case 2: case 3: case 4: case 5: throw "FAIL";
|
||||
default: j++;
|
||||
}
|
||||
}
|
||||
assertEq(i, j);
|
||||
}
|
||||
testTableSwitch1.jitstats = {
|
||||
recorderStarted: 1,
|
||||
sideExitIntoInterpreter: 1,
|
||||
recorderAborted: 0,
|
||||
traceCompleted: 1
|
||||
};
|
||||
test(testTableSwitch1);
|
||||
|
||||
function testTableSwitch2() {
|
||||
var arr = [2, 2, 2, 2, 2, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5];
|
||||
var s = '';
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
switch (arr[i]) {
|
||||
case 0: case 1: case 3: case 4:
|
||||
throw "FAIL";
|
||||
case 2:
|
||||
s += '2';
|
||||
break;
|
||||
case 5:
|
||||
s += '5';
|
||||
}
|
||||
}
|
||||
assertEq(s, arr.join(""));
|
||||
}
|
||||
testTableSwitch2.jitstats = {
|
||||
recorderStarted: 1,
|
||||
sideExitIntoInterpreter: 4,
|
||||
recorderAborted: 0,
|
||||
traceCompleted: 3
|
||||
};
|
||||
test(testTableSwitch2);
|
||||
|
||||
function testGeneratorDeepBail() {
|
||||
function g() { yield 2; }
|
||||
var iterables = [[1], [], [], [], g()];
|
||||
|
@ -5557,6 +5600,21 @@ testNativeSetter.jitstats = {
|
|||
};
|
||||
test(testNativeSetter);
|
||||
|
||||
function testBug507425() {
|
||||
var r = /x/;
|
||||
for (var i = 0; i < 3; i++)
|
||||
r.lastIndex = 0; // call a setter
|
||||
var s = ';';
|
||||
try {
|
||||
for (i = 0; i < 80; i++)
|
||||
s += s; // call js_CanLeaveTrace
|
||||
} catch (exc) {
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
testBug507425.expected = "ok";
|
||||
test(testBug507425);
|
||||
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* _____ _ _ _____ ______ _____ _______ *
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* 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 JavaScript Engine testing utilities.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dave Mandelin
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either 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
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var gTestfile = 'regress-507053.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 507053;
|
||||
var summary = 'TM: invalid results with setting a closure variable in a loop'
|
||||
var actual = '';
|
||||
var expect = '2,4,8,16,32,2,4,8,16,32,2,4,8,16,32,2,4,8,16,32,2,4,8,16,32,';
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
start_test();
|
||||
jit(true);
|
||||
|
||||
var f = function() {
|
||||
var p = 1;
|
||||
|
||||
function g() {
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
p = p * 2;
|
||||
actual += p + ',';
|
||||
}
|
||||
}
|
||||
g();
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
f();
|
||||
}
|
||||
|
||||
jit(false);
|
||||
finish_test();
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function start_test()
|
||||
{
|
||||
enterFunc ('test');
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
reportCompare(expect, actual, summary);
|
||||
exitFunc ('test');
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* 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 JavaScript Engine testing utilities.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dave Mandelin
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either 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
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var gTestfile = 'regress-507295.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 507295;
|
||||
var summary = 'TM: assert with using result of assignment to closure var'
|
||||
var actual = '';
|
||||
var expect = 'do not crash';
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
start_test();
|
||||
jit(true);
|
||||
|
||||
(function () {
|
||||
var y;
|
||||
(eval("(function () {\
|
||||
for (var x = 0; x < 3; ++x) {\
|
||||
''.replace(/a/, (y = 3))\
|
||||
}\
|
||||
});\
|
||||
"))()
|
||||
})()
|
||||
|
||||
jit(false);
|
||||
actual = 'do not crash'
|
||||
finish_test();
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function start_test()
|
||||
{
|
||||
enterFunc ('test');
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
reportCompare(expect, actual, summary);
|
||||
exitFunc ('test');
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* 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 JavaScript Engine testing utilities.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dave Mandelin
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either 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
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var gTestfile = 'regress-507424.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 507424;
|
||||
var summary = 'TM: assert with regexp literal inside closure'
|
||||
var actual = '';
|
||||
var expect = 'do not crash';
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
start_test();
|
||||
jit(true);
|
||||
|
||||
(new Function("'a'.replace(/a/,function(x){return(/x/ for each(y in[x]))})"))();
|
||||
|
||||
jit(false);
|
||||
actual = 'do not crash'
|
||||
finish_test();
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function start_test()
|
||||
{
|
||||
enterFunc ('test');
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
reportCompare(expect, actual, summary);
|
||||
exitFunc ('test');
|
||||
}
|
|
@ -541,7 +541,7 @@ pref("javascript.allow.mailnews", false);
|
|||
pref("javascript.options.strict", false);
|
||||
pref("javascript.options.relimit", false);
|
||||
pref("javascript.options.jit.content", true);
|
||||
pref("javascript.options.jit.chrome", false);
|
||||
pref("javascript.options.jit.chrome", true);
|
||||
// This preference limits the memory usage of javascript.
|
||||
// If you want to change these values for your device,
|
||||
// please find Bug 417052 comment 17 and Bug 456721
|
||||
|
|
Загрузка…
Ссылка в новой задаче