Bug 576148: Factor out js::UpvarCookie. (r=mrbkap, dvander)

This commit is contained in:
Chris Leary 2010-07-02 13:37:39 -07:00
parent c85e6d2711
commit c97ac5de82
11 changed files with 140 additions and 117 deletions

View File

@ -4139,7 +4139,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
uint32 i = 0, n = uva->length;
for (; i < n; i++) {
JSObject *obj = parent;
int skip = UPVAR_FRAME_SKIP(uva->vector[i]);
int skip = uva->vector[i].level();
while (--skip > 0) {
if (!obj) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,

View File

@ -1860,12 +1860,12 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
JSDefinition *dn = (JSDefinition *) JSVAL_TO_PRIVATE(v);
JS_ASSERT(dn->pn_defn);
JS_ASSERT(uintN(dn->frameSlot() + depth) < JS_BIT(16));
dn->pn_cookie += depth;
dn->pn_cookie.set(dn->pn_cookie.level(), dn->frameSlot() + depth);
#ifdef DEBUG
for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
JS_ASSERT(pnu->pn_lexdef == dn);
JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
JS_ASSERT(pnu->pn_cookie == FREE_UPVAR_COOKIE);
JS_ASSERT(pnu->pn_cookie.isFree());
}
#endif
}
@ -1942,13 +1942,13 @@ MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
return false;
JS_ASSERT(ALE_INDEX(ale) == cg->upvarList.count - 1);
uint32 *vector = cg->upvarMap.vector;
UpvarCookie *vector = cg->upvarMap.vector;
uint32 length = cg->upvarMap.length;
JS_ASSERT(ALE_INDEX(ale) <= length);
if (ALE_INDEX(ale) == length) {
length = 2 * JS_MAX(2, length);
vector = (uint32 *) cx->realloc(vector, length * sizeof *vector);
vector = reinterpret_cast<UpvarCookie *>(cx->realloc(vector, length * sizeof *vector));
if (!vector)
return false;
cg->upvarMap.vector = vector;
@ -1960,11 +1960,11 @@ MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
JS_ASSERT(index < JS_BIT(16));
uintN skip = cg->staticLevel - upvarLevel;
vector[ALE_INDEX(ale)] = MAKE_UPVAR_COOKIE(skip, index);
vector[ALE_INDEX(ale)].set(skip, index);
}
pn->pn_op = JSOP_GETUPVAR;
pn->pn_cookie = MAKE_UPVAR_COOKIE(cg->staticLevel, ALE_INDEX(ale));
pn->pn_cookie.set(cg->staticLevel, ALE_INDEX(ale));
pn->pn_dflags |= PND_BOUND;
return true;
}
@ -1992,7 +1992,6 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSDefinition *dn;
JSOp op;
JSAtom *atom;
uint32 cookie;
JSDefinition::Kind dn_kind;
JSAtomListElement *ale;
uintN index;
@ -2011,7 +2010,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* definitions, unless a with statement or direct eval intervened.
*/
if (pn->pn_used) {
JS_ASSERT(pn->pn_cookie == FREE_UPVAR_COOKIE);
JS_ASSERT(pn->pn_cookie.isFree());
dn = pn->pn_lexdef;
JS_ASSERT(dn->pn_defn);
if (pn->isDeoptimized())
@ -2029,7 +2028,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
atom = pn->pn_atom;
cookie = dn->pn_cookie;
UpvarCookie cookie = dn->pn_cookie;
dn_kind = dn->kind();
/*
@ -2066,7 +2065,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
pn->pn_op = op = JSOP_NAME;
}
if (cookie == FREE_UPVAR_COOKIE) {
if (cookie.isFree()) {
JSStackFrame *caller = cg->parser->callerFrame;
if (caller) {
JS_ASSERT(cg->compileAndGo());
@ -2153,12 +2152,12 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
default: JS_NOT_REACHED("gvar");
}
pn->pn_op = op;
pn->pn_cookie = cookie;
pn->pn_cookie.set(cookie);
pn->pn_dflags |= PND_BOUND;
return JS_TRUE;
}
uintN level = UPVAR_FRAME_SKIP(cookie);
uintN level = cookie.level();
JS_ASSERT(cg->staticLevel >= level);
/*
@ -2209,8 +2208,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
uintN skip = cg->staticLevel - level;
if (skip != 0) {
JS_ASSERT(cg->inFunction());
JS_ASSERT_IF(UPVAR_FRAME_SLOT(cookie) != CALLEE_UPVAR_SLOT,
cg->lexdeps.lookup(atom));
JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, cg->lexdeps.lookup(atom));
JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
JS_ASSERT(cg->fun->u.i.skipmin <= skip);
@ -2263,11 +2261,11 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
index = ALE_INDEX(ale);
JS_ASSERT(index == cg->upvarList.count - 1);
uint32 *vector = cg->upvarMap.vector;
UpvarCookie *vector = cg->upvarMap.vector;
if (!vector) {
uint32 length = cg->lexdeps.count;
vector = (uint32 *) js_calloc(length * sizeof *vector);
vector = (UpvarCookie *) js_calloc(length * sizeof *vector);
if (!vector) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
@ -2276,8 +2274,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
cg->upvarMap.length = length;
}
uintN slot = UPVAR_FRAME_SLOT(cookie);
if (slot != CALLEE_UPVAR_SLOT && dn_kind != JSDefinition::ARG) {
uintN slot = cookie.slot();
if (slot != UpvarCookie::CALLEE_SLOT && dn_kind != JSDefinition::ARG) {
JSTreeContext *tc = cg;
do {
tc = tc->parent;
@ -2286,11 +2284,12 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
slot += tc->fun->nargs;
}
vector[index] = MAKE_UPVAR_COOKIE(skip, slot);
vector[index].set(skip, slot);
}
pn->pn_op = op;
pn->pn_cookie = index;
JS_ASSERT((index & JS_BITMASK(16)) == index);
pn->pn_cookie.set(0, index);
pn->pn_dflags |= PND_BOUND;
return JS_TRUE;
}
@ -2380,7 +2379,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JS_ASSERT(op != PN_OP(pn));
pn->pn_op = op;
pn->pn_cookie = UPVAR_FRAME_SLOT(cookie);
pn->pn_cookie.set(0, cookie.slot());
pn->pn_dflags |= PND_BOUND;
return JS_TRUE;
}
@ -2556,7 +2555,7 @@ CheckSideEffects(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
if (!BindNameToSlot(cx, cg, pn))
return JS_FALSE;
if (pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE &&
pn->pn_cookie == FREE_UPVAR_COOKIE) {
pn->pn_cookie.isFree()) {
/*
* Not an argument or local variable use, and not a use of a
* unshadowed named function expression's given name, so this
@ -2636,8 +2635,8 @@ EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
if (callContext && js_Emit1(cx, cg, JSOP_NULL) < 0)
return JS_FALSE;
} else {
if (pn->pn_cookie != FREE_UPVAR_COOKIE) {
EMIT_UINT16_IMM_OP(op, pn->pn_cookie);
if (!pn->pn_cookie.isFree()) {
EMIT_UINT16_IMM_OP(op, pn->pn_cookie.asInteger());
} else {
if (!EmitAtomOp(cx, pn, op, cg))
return JS_FALSE;
@ -2748,7 +2747,7 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
if (!ale)
return JS_FALSE;
atomIndex = ALE_INDEX(ale);
return EmitSlotIndexOp(cx, op, pn2->pn_cookie, atomIndex, cg);
return EmitSlotIndexOp(cx, op, pn2->pn_cookie.asInteger(), atomIndex, cg);
}
default:;
@ -3621,8 +3620,8 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
jsatomid atomIndex;
JSAtomListElement *ale;
if (pn->pn_cookie != FREE_UPVAR_COOKIE) {
atomIndex = (jsatomid) UPVAR_FRAME_SLOT(pn->pn_cookie);
if (!pn->pn_cookie.isFree()) {
atomIndex = (jsatomid) pn->pn_cookie.slot();
} else {
ale = cg->atomList.add(cg->parser, pn->pn_atom);
if (!ale)
@ -3699,8 +3698,6 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn);
static JSBool
EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
{
jsuint slot;
/*
* Now emit the lvalue opcode sequence. If the lvalue is a nested
* destructuring initialiser-form, call ourselves to handle it, then
@ -3737,17 +3734,21 @@ EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
break;
case JSOP_SETLOCAL:
slot = (jsuint) pn->pn_cookie;
{
jsuint slot = pn->pn_cookie.asInteger();
EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
break;
}
case JSOP_SETARG:
case JSOP_SETGVAR:
slot = (jsuint) pn->pn_cookie;
{
jsuint slot = pn->pn_cookie.asInteger();
EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
if (js_Emit1(cx, cg, JSOP_POP) < 0)
return JS_FALSE;
break;
}
default:
{
@ -4141,7 +4142,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
#endif
} else {
JS_ASSERT(op != JSOP_CALLEE);
JS_ASSERT(pn2->pn_cookie != FREE_UPVAR_COOKIE || !let);
JS_ASSERT(!pn2->pn_cookie.isFree() || !let);
if (!MaybeEmitVarDecl(cx, cg, PN_OP(pn), pn2, &atomIndex))
return JS_FALSE;
@ -4207,7 +4208,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
if (op == JSOP_ARGUMENTS) {
if (js_Emit1(cx, cg, op) < 0)
return JS_FALSE;
} else if (pn2->pn_cookie != FREE_UPVAR_COOKIE) {
} else if (!pn2->pn_cookie.isFree()) {
EMIT_UINT16_IMM_OP(op, atomIndex);
} else {
EMIT_INDEX_OP(op, atomIndex);
@ -4773,7 +4774,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
: SRC_DECL_LET) < 0) {
return JS_FALSE;
}
if (pn3->pn_cookie != FREE_UPVAR_COOKIE) {
if (!pn3->pn_cookie.isFree()) {
op = PN_OP(pn3);
switch (op) {
case JSOP_GETARG: /* FALL THROUGH */
@ -4795,8 +4796,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSMSG_BAD_FOR_LEFTSIDE);
return JS_FALSE;
}
if (pn3->pn_cookie != FREE_UPVAR_COOKIE) {
atomIndex = (jsatomid) pn3->pn_cookie;
if (!pn3->pn_cookie.isFree()) {
atomIndex = (jsatomid) pn3->pn_cookie.asInteger();
EMIT_UINT16_IMM_OP(op, atomIndex);
} else {
if (!EmitAtomOp(cx, pn3, op, cg))
@ -5383,8 +5384,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
case TOK_NAME:
/* Inline and specialize BindNameToSlot for pn2. */
JS_ASSERT(pn2->pn_cookie != FREE_UPVAR_COOKIE);
EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_cookie);
JS_ASSERT(!pn2->pn_cookie.isFree());
EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_cookie.asInteger());
break;
default:
@ -5719,8 +5720,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
case TOK_NAME:
if (!BindNameToSlot(cx, cg, pn2))
return JS_FALSE;
if (pn2->pn_cookie != FREE_UPVAR_COOKIE) {
atomIndex = (jsatomid) pn2->pn_cookie;
if (!pn2->pn_cookie.isFree()) {
atomIndex = (jsatomid) pn2->pn_cookie.asInteger();
} else {
ale = cg->atomList.add(cg->parser, pn2->pn_atom);
if (!ale)
@ -6135,8 +6136,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (op == JSOP_CALLEE) {
if (js_Emit1(cx, cg, op) < 0)
return JS_FALSE;
} else if (pn2->pn_cookie != FREE_UPVAR_COOKIE) {
atomIndex = (jsatomid) pn2->pn_cookie;
} else if (!pn2->pn_cookie.isFree()) {
atomIndex = (jsatomid) pn2->pn_cookie.asInteger();
EMIT_UINT16_IMM_OP(op, atomIndex);
} else {
JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);

View File

@ -1306,23 +1306,23 @@ js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2)
return JS_TRUE;
}
jsval&
js_GetUpvar(JSContext *cx, uintN level, uintN cookie)
jsval &
js_GetUpvar(JSContext *cx, uintN level, UpvarCookie cookie)
{
level -= UPVAR_FRAME_SKIP(cookie);
level -= cookie.level();
JS_ASSERT(level < JS_DISPLAY_SIZE);
JSStackFrame *fp = cx->display[level];
JS_ASSERT(fp->script);
uintN slot = UPVAR_FRAME_SLOT(cookie);
uintN slot = cookie.slot();
jsval *vp;
if (!fp->fun || (fp->flags & JSFRAME_EVAL)) {
vp = fp->slots() + fp->script->nfixed;
} else if (slot < fp->fun->nargs) {
vp = fp->argv;
} else if (slot == CALLEE_UPVAR_SLOT) {
} else if (slot == UpvarCookie::CALLEE_SLOT) {
vp = &fp->argv[-2];
slot = 0;
} else {

View File

@ -353,8 +353,8 @@ js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp);
* 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);
extern jsval &
js_GetUpvar(JSContext *cx, uintN level, js::UpvarCookie cookie);
/*
* JS_LONE_INTERPRET indicates that the compiler should see just the code for

View File

@ -2879,7 +2879,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
}
#endif
uva = jp->script->upvars();
index = UPVAR_FRAME_SLOT(uva->vector[index]);
index = uva->vector[index].slot();
}
atom = GetArgOrVarAtom(jp, index);
goto do_name;

View File

@ -609,7 +609,7 @@ inline void
NameNode::initCommon(JSTreeContext *tc)
{
pn_expr = NULL;
pn_cookie = FREE_UPVAR_COOKIE;
pn_cookie.makeFree();
pn_dflags = tc->atTopLevel() ? PND_TOPLEVEL : 0;
if (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
pn_dflags |= PND_BLOCKCHILD;
@ -687,21 +687,16 @@ Parser::parse(JSObject *chain)
return pn;
}
JS_STATIC_ASSERT(FREE_STATIC_LEVEL == JS_BITMASK(JSFB_LEVEL_BITS));
JS_STATIC_ASSERT(UpvarCookie::FREE_LEVEL == JS_BITMASK(JSFB_LEVEL_BITS));
static inline bool
SetStaticLevel(JSTreeContext *tc, uintN staticLevel)
{
/*
* 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.
* This is a lot simpler than error-checking every UpvarCookie::set, and
* practically speaking it leaves more than enough room for upvars.
*/
if (staticLevel >= FREE_STATIC_LEVEL) {
if (UpvarCookie::isLevelReserved(staticLevel)) {
JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL,
JSMSG_TOO_DEEP, js_function_str);
return false;
@ -1453,7 +1448,7 @@ MakeDefIntoUse(JSDefinition *dn, JSParseNode *pn, JSAtom *atom, JSTreeContext *t
dn->pn_defn = false;
dn->pn_used = true;
dn->pn_lexdef = (JSDefinition *) pn;
dn->pn_cookie = FREE_UPVAR_COOKIE;
dn->pn_cookie.makeFree();
dn->pn_dflags &= ~PND_BOUND;
return dn;
}
@ -1497,7 +1492,7 @@ DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc)
argsbody->append(argpn);
argpn->pn_op = JSOP_GETARG;
argpn->pn_cookie = MAKE_UPVAR_COOKIE(tc->staticLevel, i);
argpn->pn_cookie.set(tc->staticLevel, i);
argpn->pn_dflags |= PND_BOUND;
return true;
}
@ -1540,7 +1535,7 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin
JSParseNode *fn = FunctionNode::create(&funcg);
if (fn) {
fn->pn_body = NULL;
fn->pn_cookie = FREE_UPVAR_COOKIE;
fn->pn_cookie.makeFree();
uintN nargs = fun->nargs;
if (nargs) {
@ -1675,7 +1670,7 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
if (!BindLocalVariable(cx, tc->fun, atom, JSLOCAL_VAR, true))
return JS_FALSE;
pn->pn_op = JSOP_SETLOCAL;
pn->pn_cookie = MAKE_UPVAR_COOKIE(tc->staticLevel, index);
pn->pn_cookie.set(tc->staticLevel, index);
pn->pn_dflags |= PND_BOUND;
return JS_TRUE;
}
@ -1765,7 +1760,7 @@ Parser::analyzeFunctions(JSFunctionBox *funbox, uint32& tcflags)
static uintN
FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue)
{
uintN allskipmin = FREE_STATIC_LEVEL;
uintN allskipmin = UpvarCookie::FREE_LEVEL;
do {
JSParseNode *fn = funbox->node;
@ -1790,7 +1785,7 @@ FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue)
* an upvar, whether used directly by fun, or indirectly by a function
* nested in fun.
*/
uintN skipmin = FREE_STATIC_LEVEL;
uintN skipmin = UpvarCookie::FREE_LEVEL;
JSParseNode *pn = fn->pn_body;
if (pn->pn_type == TOK_UPVARS) {
@ -1836,7 +1831,7 @@ FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue)
uintN kidskipmin = FindFunArgs(funbox->kids, fnlevel, queue);
JS_ASSERT(kidskipmin != 0);
if (kidskipmin != FREE_STATIC_LEVEL) {
if (kidskipmin != UpvarCookie::FREE_LEVEL) {
--kidskipmin;
if (kidskipmin != 0 && kidskipmin < skipmin)
skipmin = kidskipmin;
@ -1849,7 +1844,7 @@ FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue)
* with allskipmin, but minimize across funbox and all of its siblings,
* to compute our return value.
*/
if (skipmin != FREE_STATIC_LEVEL) {
if (skipmin != UpvarCookie::FREE_LEVEL) {
fun->u.i.skipmin = skipmin;
if (skipmin < allskipmin)
allskipmin = skipmin;
@ -1908,7 +1903,7 @@ Parser::markFunArgs(JSFunctionBox *funbox, uintN tcflags)
* See bug 545980.
*/
afunbox = funbox;
uintN calleeLevel = UPVAR_FRAME_SKIP(lexdep->pn_cookie);
uintN calleeLevel = lexdep->pn_cookie.level();
uintN staticLevel = afunbox->level + 1U;
while (staticLevel != calleeLevel) {
afunbox = afunbox->parent;
@ -2433,7 +2428,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, JSAtom *funAtom = NULL,
if (atom == funAtom && lambda != 0) {
dn->pn_op = JSOP_CALLEE;
dn->pn_cookie = MAKE_UPVAR_COOKIE(funtc->staticLevel, CALLEE_UPVAR_SLOT);
dn->pn_cookie.set(funtc->staticLevel, UpvarCookie::CALLEE_SLOT);
dn->pn_dflags |= PND_BOUND;
/*
@ -2556,7 +2551,7 @@ Parser::functionDef(uintN lambda, bool namePermitted)
if (!pn)
return NULL;
pn->pn_body = NULL;
pn->pn_cookie = FREE_UPVAR_COOKIE;
pn->pn_cookie.makeFree();
/*
* If a lambda, give up on JSOP_{GET,CALL}UPVAR usage unless this function
@ -2636,7 +2631,7 @@ Parser::functionDef(uintN lambda, bool namePermitted)
fn->pn_arity = PN_FUNC;
fn->pn_pos.begin = pn->pn_pos.begin;
fn->pn_body = NULL;
fn->pn_cookie = FREE_UPVAR_COOKIE;
fn->pn_cookie.makeFree();
tc->lexdeps.rawRemove(tc->parser, ale, hep);
RecycleTree(pn, tc);
@ -2679,7 +2674,7 @@ Parser::functionDef(uintN lambda, bool namePermitted)
/* FALL THROUGH */
case JSLOCAL_VAR:
pn->pn_cookie = MAKE_UPVAR_COOKIE(tc->staticLevel, index);
pn->pn_cookie.set(tc->staticLevel, index);
pn->pn_dflags |= PND_BOUND;
break;
@ -2753,7 +2748,7 @@ Parser::functionDef(uintN lambda, bool namePermitted)
return NULL;
rhs->pn_type = TOK_NAME;
rhs->pn_op = JSOP_GETARG;
rhs->pn_cookie = MAKE_UPVAR_COOKIE(funtc.staticLevel, slot);
rhs->pn_cookie.set(funtc.staticLevel, slot);
rhs->pn_dflags |= PND_BOUND;
item = JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc);
@ -3173,7 +3168,7 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
* include script->nfixed.
*/
pn->pn_op = JSOP_GETLOCAL;
pn->pn_cookie = MAKE_UPVAR_COOKIE(tc->staticLevel, n);
pn->pn_cookie.set(tc->staticLevel, n);
pn->pn_dflags |= PND_LET | PND_BOUND;
/*
@ -3271,7 +3266,7 @@ BindGvar(JSParseNode *pn, JSTreeContext *tc, bool inWith = false)
if (!inWith) {
pn->pn_op = JSOP_GETGVAR;
pn->pn_cookie = MAKE_UPVAR_COOKIE(tc->staticLevel, slot);
pn->pn_cookie.set(tc->staticLevel, slot);
pn->pn_dflags |= PND_BOUND | PND_GVAR;
}
}
@ -3454,7 +3449,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
if (!BindLocalVariable(cx, tc->fun, atom, localKind, false))
return JS_FALSE;
pn->pn_op = JSOP_GETLOCAL;
pn->pn_cookie = MAKE_UPVAR_COOKIE(tc->staticLevel, index);
pn->pn_cookie.set(tc->staticLevel, index);
pn->pn_dflags |= PND_BOUND;
return JS_TRUE;
}
@ -3506,16 +3501,8 @@ NoteLValue(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN dflag = PND_
dn->pn_dflags |= dflag;
if (dn->frameLevel() != tc->staticLevel) {
/*
* The above condition takes advantage of the all-ones nature of
* FREE_UPVAR_COOKIE, and the reserved level FREE_STATIC_LEVEL.
* We make a stronger assertion by excluding FREE_UPVAR_COOKIE.
*/
JS_ASSERT_IF(dn->pn_cookie != FREE_UPVAR_COOKIE,
dn->frameLevel() < tc->staticLevel);
if (dn->pn_cookie.isFree() || dn->frameLevel() < tc->staticLevel)
tc->flags |= TCF_FUN_SETS_OUTER_NAME;
}
}
pn->pn_dflags |= dflag;
@ -4285,7 +4272,7 @@ PushLexicalScope(JSContext *cx, TokenStream *ts, JSTreeContext *tc,
pn->pn_type = TOK_LEXICALSCOPE;
pn->pn_op = JSOP_LEAVEBLOCK;
pn->pn_objbox = blockbox;
pn->pn_cookie = FREE_UPVAR_COOKIE;
pn->pn_cookie.makeFree();
pn->pn_dflags = 0;
if (!GenerateBlockId(tc, stmt->blockid))
return NULL;
@ -6317,17 +6304,17 @@ class CompExprTransplanter {
static bool
BumpStaticLevel(JSParseNode *pn, JSTreeContext *tc)
{
if (pn->pn_cookie != FREE_UPVAR_COOKIE) {
uintN level = UPVAR_FRAME_SKIP(pn->pn_cookie) + 1;
if (!pn->pn_cookie.isFree()) {
uintN level = pn->pn_cookie.level() + 1;
JS_ASSERT(level >= tc->staticLevel);
if (level >= FREE_STATIC_LEVEL) {
if (level >= UpvarCookie::FREE_LEVEL) {
JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL,
JSMSG_TOO_DEEP, js_function_str);
return false;
}
pn->pn_cookie = MAKE_UPVAR_COOKIE(level, UPVAR_FRAME_SLOT(pn->pn_cookie));
pn->pn_cookie.set(level, pn->pn_cookie.slot());
}
return true;
}
@ -6414,7 +6401,7 @@ CompExprTransplanter::transplant(JSParseNode *pn)
return false;
} else if (pn->pn_used) {
JS_ASSERT(pn->pn_op != JSOP_NOP);
JS_ASSERT(pn->pn_cookie == FREE_UPVAR_COOKIE);
JS_ASSERT(pn->pn_cookie.isFree());
JSDefinition *dn = pn->pn_lexdef;
JS_ASSERT(dn->pn_defn);
@ -7145,7 +7132,7 @@ Parser::propertySelector()
pn->pn_op = JSOP_QNAMEPART;
pn->pn_arity = PN_NAME;
pn->pn_atom = tokenStream.currentToken().t_atom;
pn->pn_cookie = FREE_UPVAR_COOKIE;
pn->pn_cookie.makeFree();
}
return pn;
}
@ -7174,7 +7161,7 @@ Parser::qualifiedSuffix(JSParseNode *pn)
? context->runtime->atomState.starAtom
: tokenStream.currentToken().t_atom;
pn2->pn_expr = pn;
pn2->pn_cookie = FREE_UPVAR_COOKIE;
pn2->pn_cookie.makeFree();
return pn2;
}

View File

@ -339,7 +339,7 @@ struct JSParseNode {
base object of TOK_DOT */
JSDefinition *lexdef; /* lexical definition for this use */
};
uint32 cookie; /* upvar cookie with absolute frame
js::UpvarCookie cookie; /* upvar cookie with absolute frame
level (not relative skip), possibly
in current frame */
uint32 dflags:12, /* definition/use flags, see below */
@ -465,12 +465,12 @@ public:
uintN frameLevel() const {
JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
return UPVAR_FRAME_SKIP(pn_cookie);
return pn_cookie.level();
}
uintN frameSlot() const {
JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
return UPVAR_FRAME_SLOT(pn_cookie);
return pn_cookie.slot();
}
inline bool test(uintN flag) const;
@ -767,7 +767,7 @@ struct JSDefinition : public JSParseNode
bool isFreeVar() const {
JS_ASSERT(pn_defn);
return pn_cookie == FREE_UPVAR_COOKIE || test(PND_GVAR);
return pn_cookie.isFree() || test(PND_GVAR);
}
// Grr, windows.h or something under it #defines CONST...

View File

@ -327,7 +327,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
}
}
for (i = 0; i != nupvars; ++i) {
if (!JS_XDRUint32(xdr, &script->upvars()->vector[i]))
if (!JS_XDRUint32(xdr, reinterpret_cast<uint32 *>(&script->upvars()->vector[i])))
goto error;
}
for (i = 0; i != nregexps; ++i) {
@ -894,7 +894,7 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
*/
if (nupvars != 0) {
script->upvars()->length = nupvars;
script->upvars()->vector = (uint32 *)cursor;
script->upvars()->vector = reinterpret_cast<UpvarCookie *>(cursor);
vectorSize = nupvars * sizeof(script->upvars()->vector[0]);
memset(cursor, 0, vectorSize);
cursor += vectorSize;

View File

@ -59,6 +59,50 @@ typedef enum JSTryNoteKind {
JSTRY_ITER
} JSTryNoteKind;
namespace js {
/*
* Indicates a location in the stack that an upvar value can be retrieved from
* as a two tuple of (level, slot).
*
* Some existing client code uses the level value as a delta, or level "skip"
* quantity. We could probably document that through use of more types at some
* point in the future.
*
* Existing XDR code wants this to be backed by a 32b integer for serialization,
* so we oblige.
*
* TODO: consider giving more bits to the slot value and takings ome from the level.
*/
class UpvarCookie
{
uint32 value;
static const uint32 FREE_VALUE = 0xfffffffful;
public:
/*
* All levels above-and-including FREE_LEVEL are reserved so that
* FREE_VALUE can be used as a special value.
*/
static const uint16 FREE_LEVEL = 0x3fff;
static const uint16 CALLEE_SLOT = 0xffff;
static bool isLevelReserved(uint16 level) { return level >= FREE_LEVEL; }
bool isFree() const { return value == FREE_VALUE; }
uint32 asInteger() const { return value; }
/* isFree check should be performed before using these accessors. */
uint16 level() const { JS_ASSERT(!isFree()); return value >> 16; }
uint16 slot() const { JS_ASSERT(!isFree()); return value; }
void set(const UpvarCookie &other) { set(other.level(), other.slot()); }
void set(uint16 newLevel, uint16 newSlot) { value = (uint32(newLevel) << 16) | newSlot; }
void makeFree() { set(0xffff, 0xffff); JS_ASSERT(isFree()); }
};
JS_STATIC_ASSERT(sizeof(UpvarCookie) == sizeof(uint32));
}
/*
* Exception handling record.
*/
@ -82,17 +126,10 @@ typedef struct JSObjectArray {
} JSObjectArray;
typedef struct JSUpvarArray {
uint32 *vector; /* array of indexed upvar cookies */
js::UpvarCookie *vector; /* array of indexed upvar cookies */
uint32 length; /* count of indexed upvar cookies */
} JSUpvarArray;
#define CALLEE_UPVAR_SLOT 0xffff
#define FREE_STATIC_LEVEL 0x3fff
#define FREE_UPVAR_COOKIE 0xffffffff
#define MAKE_UPVAR_COOKIE(skip,slot) ((skip) << 16 | (slot))
#define UPVAR_FRAME_SKIP(cookie) ((uint32)(cookie) >> 16)
#define UPVAR_FRAME_SLOT(cookie) ((uint16)(cookie))
#define JS_OBJECT_ARRAY_SIZE(length) \
(offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length))

View File

@ -12509,7 +12509,7 @@ TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v)
* It does not work to assign the result to v, because v is an already
* existing reference that points to something else.
*/
uint32 cookie = uva->vector[index];
UpvarCookie cookie = uva->vector[index];
jsval& vr = js_GetUpvar(cx, script->staticLevel, cookie);
v = vr;
@ -12520,8 +12520,8 @@ TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v)
* The upvar is not in the current trace, so get the upvar value exactly as
* the interpreter does and unbox.
*/
uint32 level = script->staticLevel - UPVAR_FRAME_SKIP(cookie);
uint32 cookieSlot = UPVAR_FRAME_SLOT(cookie);
uint32 level = script->staticLevel - cookie.level();
uint32 cookieSlot = cookie.slot();
JSStackFrame* fp = cx->display[level];
const CallInfo* ci;
int32 slot;
@ -12531,7 +12531,7 @@ TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v)
} else if (cookieSlot < fp->fun->nargs) {
ci = &GetUpvarArgOnTrace_ci;
slot = cookieSlot;
} else if (cookieSlot == CALLEE_UPVAR_SLOT) {
} else if (cookieSlot == UpvarCookie::CALLEE_SLOT) {
ci = &GetUpvarArgOnTrace_ci;
slot = -2;
} else {

View File

@ -1772,12 +1772,10 @@ DisassembleValue(JSContext *cx, jsval v, bool lines, bool recursive)
for (uint32 i = 0, n = uva->length; i < n; i++) {
JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[upvar_base + i]);
uint32 cookie = uva->vector[i];
UpvarCookie cookie = uva->vector[i];
printf(" %s: {skip:%u, slot:%u},\n",
js_AtomToPrintableString(cx, atom),
UPVAR_FRAME_SKIP(cookie),
UPVAR_FRAME_SLOT(cookie));
js_AtomToPrintableString(cx, atom), cookie.level(), cookie.slot());
}
JS_ARENA_RELEASE(&cx->tempPool, mark);