Bug 487563 - Crash [@ js_Interpret] (r=mrbkap).

This commit is contained in:
Brendan Eich 2009-04-09 18:44:54 -07:00
Родитель c57536e84b
Коммит ba72ca8b21
7 изменённых файлов: 62 добавлений и 57 удалений

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

@ -2205,26 +2205,9 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun)
JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
JS_ASSERT(uva->length <= size_t(closure->dslots[-1]));
for (uint32 i = 0, n = uva->length; i < n; i++) {
uint32 cookie = uva->vector[i];
uintN upvarLevel = fun->u.i.script->staticLevel - UPVAR_FRAME_SKIP(cookie);
JS_ASSERT(upvarLevel <= JS_DISPLAY_SIZE);
JSStackFrame *fp2 = cx->display[upvarLevel];
uintN slot = UPVAR_FRAME_SLOT(cookie);
jsval *vp;
if (fp2->fun && slot < fp2->fun->nargs) {
vp = fp2->argv;
} else {
if (fp2->fun)
slot -= fp2->fun->nargs;
JS_ASSERT(slot < fp2->script->nslots);
vp = fp2->slots;
}
closure->dslots[i] = vp[slot];
}
uintN level = fun->u.i.script->staticLevel;
for (uint32 i = 0, n = uva->length; i < n; i++)
closure->dslots[i] = js_GetUpvar(cx, level, uva->vector[i]);
return closure;
}

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

@ -2054,6 +2054,34 @@ js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2)
return JS_TRUE;
}
jsval
js_GetUpvar(JSContext *cx, uintN level, uintN cookie)
{
level -= UPVAR_FRAME_SKIP(cookie);
JS_ASSERT(level < JS_DISPLAY_SIZE);
JSStackFrame *fp = cx->display[level];
JS_ASSERT(fp->script);
uintN slot = UPVAR_FRAME_SLOT(cookie);
jsval *vp;
if (!fp->fun) {
vp = fp->slots + fp->script->nfixed;
} else if (slot < fp->fun->nargs) {
vp = fp->argv;
} else if (slot == CALLEE_UPVAR_SLOT) {
vp = &fp->argv[-2];
slot = 0;
} else {
slot -= fp->fun->nargs;
JS_ASSERT(slot < fp->script->nslots);
vp = fp->slots;
}
return vp[slot];
}
#ifdef DEBUG
JS_STATIC_INTERPRET JS_REQUIRES_STACK void
@ -5682,29 +5710,14 @@ js_Interpret(JSContext *cx)
BEGIN_CASE(JSOP_GETUPVAR)
BEGIN_CASE(JSOP_CALLUPVAR)
{
JSUpvarArray *uva;
uint32 skip;
JSStackFrame *fp2;
JSUpvarArray *uva = JS_SCRIPT_UPVARS(script);
index = GET_UINT16(regs.pc);
uva = JS_SCRIPT_UPVARS(script);
JS_ASSERT(index < uva->length);
skip = UPVAR_FRAME_SKIP(uva->vector[index]);
fp2 = cx->display[script->staticLevel - skip];
JS_ASSERT(fp2->script);
slot = UPVAR_FRAME_SLOT(uva->vector[index]);
if (!fp2->fun) {
vp = fp2->slots + fp2->script->nfixed;
} else if (slot < fp2->fun->nargs) {
vp = fp2->argv;
} else {
slot -= fp2->fun->nargs;
JS_ASSERT(slot < fp2->script->nslots);
vp = fp2->slots;
}
rval = js_GetUpvar(cx, script->staticLevel, uva->vector[index]);
PUSH_OPND(rval);
PUSH_OPND(vp[slot]);
if (op == JSOP_CALLUPVAR)
PUSH_OPND(JSVAL_NULL);
}

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

@ -606,6 +606,13 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp);
extern JSBool
js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2);
/*
* Given an active context, a static scope level, and an upvar cookie, return
* the value of the upvar.
*/
extern jsval
js_GetUpvar(JSContext *cx, uintN level, uintN cookie);
/*
* Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the
* previous opcode.

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

@ -748,13 +748,15 @@ static inline bool
SetStaticLevel(JSTreeContext *tc, uintN staticLevel)
{
/*
* Reserve staticLevel 0xffff in order to reserve FREE_UPVAR_COOKIE. This
* is simpler than error-checking every MAKE_UPVAR_COOKIE, and practically
* speaking it leaves more than enough room for upvars. In fact we might
* want to split cookies with fewer bits for skip and more for slot, but
* only based on evidence.
* Reserve FREE_STATIC_LEVEL (0xffff) in order to reserve FREE_UPVAR_COOKIE
* (0xffffffff) and other cookies with that level.
*
* This is a lot simpler than error-checking every MAKE_UPVAR_COOKIE, and
* practically speaking it leaves more than enough room for upvars. In fact
* we might want to split cookie fields giving fewer bits for skip and more
* for slot, but only based on evidence.
*/
if (staticLevel >= JS_BITMASK(16)) {
if (staticLevel >= FREE_STATIC_LEVEL) {
JS_ReportErrorNumber(tc->compiler->context, js_GetErrorMessage, NULL,
JSMSG_TOO_DEEP, js_function_str);
return false;
@ -2198,7 +2200,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, JSTreeContext *tc,
if (atom == funAtom && lambda != 0) {
dn->pn_op = JSOP_CALLEE;
dn->pn_cookie = MAKE_UPVAR_COOKIE(funtc->staticLevel, 0);
dn->pn_cookie = MAKE_UPVAR_COOKIE(funtc->staticLevel, CALLEE_UPVAR_SLOT);
dn->pn_dflags |= PND_BOUND;
/*
@ -2211,7 +2213,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, JSTreeContext *tc,
* code unfairly (see JSCompiler::setFunctionKinds, where this
* flag is interpreted in its broader sense, not only to mean
* "this function might leak arguments.callee"), we can perhaps
* try to work harder to add a TCF_FUN_CALLS_ITSELF flag and
* try to work harder to add a TCF_FUN_LEAKS_ITSELF flag and
* use that more precisely, both here and for unnamed function
* expressions.
*/
@ -7875,7 +7877,6 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
} else if (!afterDot && !(ts->flags & TSF_DESTRUCTURING)) {
JSAtomListElement *ale = NULL;
JSTreeContext *tcx = tc;
bool hit_named_lambda = false;
JSDefinition *dn;
do {
@ -7898,10 +7899,9 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
}
/* If this id names the current lambda's name, we are done. */
if ((tc->flags & TCF_IN_FUNCTION) &&
(tc->fun->flags & JSFUN_LAMBDA) &&
tc->fun->atom == pn->pn_atom) {
hit_named_lambda = true;
if ((tcx->flags & TCF_IN_FUNCTION) &&
(tcx->fun->flags & JSFUN_LAMBDA) &&
tcx->fun->atom == pn->pn_atom) {
break;
}
} while ((tcx = tcx->parent) != NULL);
@ -7950,14 +7950,17 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
* a backward definition appears later; see NewBindingNode/Define).
*
* (b) If pn names the named function expression whose body we are
* parsing, there's no way an upvar could be referenced here.
* parsing, there's no way an upvar above tcx's static level could
* be referenced here. However, we add to upvars anyway, to treat
* the function's name as an upvar in case it is used in a nested
* function.
*
* (a) is is an optimization to handle forward upvar refs. Without
* it, if we add only a lexdep, then inner functions making forward
* refs to upvars will lose track of those upvars as their lexdeps
* entries are propagated upward to their parent functions.
*/
if (tcx != tc && !hit_named_lambda) {
if (tcx != tc) {
ale = tc->upvars.add(tc->compiler, pn->pn_atom);
if (!ale)
return NULL;

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

@ -86,6 +86,8 @@ typedef struct JSUpvarArray {
uint32 length; /* count of indexed upvar cookies */
} JSUpvarArray;
#define CALLEE_UPVAR_SLOT 0xffff
#define FREE_STATIC_LEVEL 0xffff
#define FREE_UPVAR_COOKIE 0xffffffff
#define MAKE_UPVAR_COOKIE(skip,slot) ((skip) << 16 | (slot))
#define UPVAR_FRAME_SKIP(cookie) ((uint32)(cookie) >> 16)

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

@ -367,9 +367,6 @@ struct InterpState
#ifdef EXECUTE_TREE_TIMER
uint64 startTime;
#endif
#ifdef DEBUG
bool jsframe_pop_blocks_set_on_entry;
#endif
/*
* Used by _FAIL builtins; see jsbuiltins.h. The builtin sets the

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

@ -204,7 +204,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
* before deserialization of bytecode. If the saved version does not match
* the current version, abort deserialization and invalidate the file.
*/
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 44)
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 45)
/*
* Library-private functions.