Merge tracemonkey to mozilla-central.

This commit is contained in:
Robert Sayre 2009-08-03 10:29:28 -07:00
Родитель 3367dceb3e 7cbf6577c7
Коммит 21991120d1
26 изменённых файлов: 1038 добавлений и 166 удалений

Просмотреть файл

@ -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@

Просмотреть файл

@ -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, &ethogram_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, &ethogram_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, &ethogram_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, &ethogram_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, &ethogram_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, &ethogram_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