From 95a28c72058a2f9df131244c8e7a618393a5365b Mon Sep 17 00:00:00 2001 From: Chris Leary Date: Fri, 2 Jul 2010 13:37:39 -0700 Subject: [PATCH] Bug 576148: Factor out js::UpvarCookie. (r=mrbkap, dvander) --- js/src/jsapi.cpp | 2 +- js/src/jsemit.cpp | 85 +++++++++++++++++++++++++++-------------------------- js/src/jsinterp.cpp | 10 +++---- js/src/jsinterp.h | 4 +-- js/src/jsopcode.cpp | 2 +- js/src/jsparse.cpp | 75 +++++++++++++++++++--------------------------- js/src/jsparse.h | 8 ++--- js/src/jsscript.cpp | 4 +-- js/src/jsscript.h | 53 ++++++++++++++++++++++++++++----- js/src/jstracer.cpp | 8 ++--- js/src/shell/js.cpp | 6 ++-- 11 files changed, 140 insertions(+), 117 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 6e6785fbc5..0c575943aa 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -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, diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index f324de91f7..9776cedb49 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -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(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); diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 6a5c0b5d19..8ca8ce9ab8 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -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 { diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index afdb6fc27c..1749c734fe 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -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 diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index e64a3835f4..ee045c9fe3 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -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; diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 5ed773ca32..e75984a61a 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -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; } diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 30c2d8b997..40799885b9 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -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... diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 17f4d0d139..850c6f4066 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -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(&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(cursor); vectorSize = nupvars * sizeof(script->upvars()->vector[0]); memset(cursor, 0, vectorSize); cursor += vectorSize; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 37658c2e32..2de5a5e42c 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -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)) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index f891e28665..a06ad5ae5d 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -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 { diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 296dcc790c..d6efe9fb9e 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -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); -- 2.11.4.GIT