diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 62655708d508..b559b3a70f96 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1252,7 +1252,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) * Don't generate upvars on the left side of a for loop. See * bug 470758. */ - if (bce->sc->flags & TCF_IN_FOR_INIT) + if (bce->sc->inForInit) return JS_TRUE; JS_ASSERT(caller->isScriptFrame()); @@ -1682,11 +1682,11 @@ EmitXMLName(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME); ParseNode *pn2 = pn->pn_kid; - unsigned oldflags = bce->sc->flags; - bce->sc->flags &= ~TCF_IN_FOR_INIT; + bool oldInForInit = bce->sc->inForInit; + bce->sc->inForInit = false; if (!EmitTree(cx, bce, pn2)) return false; - bce->sc->flags |= oldflags & TCF_IN_FOR_INIT; + bce->sc->inForInit = oldInForInit; if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pn2->pn_offset) < 0) return false; @@ -3375,11 +3375,11 @@ EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption return JS_FALSE; } - unsigned oldflags = bce->sc->flags; - bce->sc->flags &= ~TCF_IN_FOR_INIT; + bool oldInForInit = bce->sc->inForInit; + bce->sc->inForInit = false; if (!EmitTree(cx, bce, pn3)) return JS_FALSE; - bce->sc->flags |= oldflags & TCF_IN_FOR_INIT; + bce->sc->inForInit = oldInForInit; } else if (letNotes) { /* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */ if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) @@ -4526,10 +4526,10 @@ EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) if (pn1) { ParseNode *decl = letDecl ? pn1->pn_expr : pn1; JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET)); - bce->sc->flags |= TCF_IN_FOR_INIT; + bce->sc->inForInit = true; if (!EmitVariables(cx, bce, decl, DefineVars)) return false; - bce->sc->flags &= ~TCF_IN_FOR_INIT; + bce->sc->inForInit = false; } /* Compile the object expression to the right of 'in'. */ @@ -4669,7 +4669,7 @@ EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) /* No initializer: emit an annotated nop for the decompiler. */ op = JSOP_NOP; } else { - bce->sc->flags |= TCF_IN_FOR_INIT; + bce->sc->inForInit = true; #if JS_HAS_DESTRUCTURING if (pn3->isKind(PNK_ASSIGN)) { JS_ASSERT(pn3->isOp(JSOP_NOP)); @@ -4692,7 +4692,7 @@ EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) op = JSOP_NOP; } } - bce->sc->flags &= ~TCF_IN_FOR_INIT; + bce->sc->inForInit = false; } /* @@ -5394,13 +5394,13 @@ EmitCallOrNew(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) * JSOP_NEW bytecode with a two-byte immediate telling how many args * were pushed on the operand stack. */ - unsigned oldflags = bce->sc->flags; - bce->sc->flags &= ~TCF_IN_FOR_INIT; + bool oldInForInit = bce->sc->inForInit; + bce->sc->inForInit = false; for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) { if (!EmitTree(cx, bce, pn3)) return false; } - bce->sc->flags |= oldflags & TCF_IN_FOR_INIT; + bce->sc->inForInit = oldInForInit; if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - off) < 0) return false; @@ -5880,12 +5880,12 @@ EmitUnary(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (op == JSOP_TYPEOF && !pn2->isKind(PNK_NAME)) op = JSOP_TYPEOFEXPR; - unsigned oldflags = bce->sc->flags; - bce->sc->flags &= ~TCF_IN_FOR_INIT; + bool oldInForInit = bce->sc->inForInit; + bce->sc->inForInit = false; if (!EmitTree(cx, bce, pn2)) return false; - bce->sc->flags |= oldflags & TCF_IN_FOR_INIT; + bce->sc->inForInit = oldInForInit; return Emit1(cx, bce, op) >= 0; } @@ -6116,7 +6116,6 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) } } else { #if JS_HAS_XML_SUPPORT - unsigned oldflags; case PNK_DBLCOLON: JS_ASSERT(pn->getOp() != JSOP_XMLNAME); @@ -6131,10 +6130,10 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) /* * Binary :: has a right operand that brackets arbitrary code, * possibly including a let (a = b) ... expression. We must clear - * TCF_IN_FOR_INIT to avoid mis-compiling such beasts. + * inForInit to avoid mis-compiling such beasts. */ - oldflags = bce->sc->flags; - bce->sc->flags &= ~TCF_IN_FOR_INIT; + bool oldInForInit = bce->sc->inForInit; + bce->sc->inForInit = false; #endif /* Binary operators that evaluate both operands unconditionally. */ @@ -6143,7 +6142,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (!EmitTree(cx, bce, pn->pn_right)) return JS_FALSE; #if JS_HAS_XML_SUPPORT - bce->sc->flags |= oldflags & TCF_IN_FOR_INIT; + bce->sc->inForInit = oldInForInit; #endif if (Emit1(cx, bce, pn->getOp()) < 0) return JS_FALSE; @@ -6158,11 +6157,11 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) } else { JSOp op = pn->getOp(); JS_ASSERT(op == JSOP_BINDXMLNAME || op == JSOP_SETXMLNAME); - unsigned oldflags = bce->sc->flags; - bce->sc->flags &= ~TCF_IN_FOR_INIT; + bool oldInForInit = bce->sc->inForInit; + bce->sc->inForInit = false; if (!EmitTree(cx, bce, pn->pn_kid)) return false; - bce->sc->flags |= oldflags & TCF_IN_FOR_INIT; + bce->sc->inForInit = oldInForInit; if (Emit1(cx, bce, op) < 0) return false; } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 2f870cae4240..bce4304c2cf0 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3104,7 +3104,7 @@ Parser::forStatement() /* * Set pn1 to a var list or an initializing expression. * - * Set the TCF_IN_FOR_INIT flag during parsing of the first clause + * Set the inForInit flag during parsing of the first clause * of the for statement. This flag will be used by the RelExpr * production; if it is set, then the 'in' keyword will not be * recognized as an operator, leaving it available to be parsed as @@ -3114,7 +3114,7 @@ Parser::forStatement() * expressions involving an 'in' operator are illegal in the init * clause of an ordinary for loop. */ - tc->sc->flags |= TCF_IN_FOR_INIT; + tc->sc->inForInit = true; if (tt == TOK_VAR || tt == TOK_CONST) { forDecl = true; tokenStream.consumeKnownToken(tt); @@ -3137,7 +3137,7 @@ Parser::forStatement() else { pn1 = expr(); } - tc->sc->flags &= ~TCF_IN_FOR_INIT; + tc->sc->inForInit = false; if (!pn1) return NULL; } @@ -3155,7 +3155,7 @@ Parser::forStatement() * We can be sure that it's a for/in loop if there's still an 'in' * keyword here, even if JavaScript recognizes 'in' as an operator, * as we've excluded 'in' from being parsed in RelExpr by setting - * the TCF_IN_FOR_INIT flag in our TreeContext. + * tc->sc->inForInit. */ ParseNode *forHead; /* initialized by both branches. */ StmtInfo letStmt(context); /* used if blockObj != NULL. */ @@ -4217,7 +4217,7 @@ Parser::variables(ParseNodeKind kind, StaticBlockObject *blockObj, VarContext va if (!CheckDestructuring(context, &data, pn2, this)) return NULL; bool ignored; - if ((tc->sc->flags & TCF_IN_FOR_INIT) && matchInOrOf(&ignored)) { + if (tc->sc->inForInit && matchInOrOf(&ignored)) { tokenStream.ungetToken(); pn->append(pn2); continue; @@ -4420,13 +4420,12 @@ RelationalTokenToParseNodeKind(const Token &token) BEGIN_EXPR_PARSER(relExpr1) { - unsigned inForInitFlag = tc->sc->flags & TCF_IN_FOR_INIT; - /* * Uses of the in operator in shiftExprs are always unambiguous, * so unset the flag that prohibits recognizing it. */ - tc->sc->flags &= ~TCF_IN_FOR_INIT; + bool oldInForInit = tc->sc->inForInit; + tc->sc->inForInit = false; ParseNode *pn = shiftExpr1i(); while (pn && @@ -4435,14 +4434,14 @@ BEGIN_EXPR_PARSER(relExpr1) * Recognize the 'in' token as an operator only if we're not * currently in the init expr of a for loop. */ - (inForInitFlag == 0 && tokenStream.isCurrentTokenType(TOK_IN)) || + (oldInForInit == 0 && tokenStream.isCurrentTokenType(TOK_IN)) || tokenStream.isCurrentTokenType(TOK_INSTANCEOF))) { ParseNodeKind kind = RelationalTokenToParseNodeKind(tokenStream.currentToken()); JSOp op = tokenStream.currentToken().t_op; pn = ParseNode::newBinaryOrAppend(kind, op, pn, shiftExpr1n(), this); } /* Restore previous state of inForInit flag. */ - tc->sc->flags |= inForInitFlag; + tc->sc->inForInit |= oldInForInit; return pn; } @@ -4536,10 +4535,12 @@ Parser::condExpr1() * where it's unambiguous, even if we might be parsing the init of a * for statement. */ - unsigned oldflags = tc->sc->flags; - tc->sc->flags &= ~TCF_IN_FOR_INIT; + uint32_t oldflags = tc->sc->flags; + bool oldInForInit = tc->sc->inForInit; + tc->sc->inForInit = false; ParseNode *thenExpr = assignExpr(); tc->sc->flags = oldflags | (tc->sc->flags & TCF_FUN_FLAGS); + tc->sc->inForInit = oldInForInit; if (!thenExpr) return NULL; @@ -5803,18 +5804,17 @@ Parser::memberExpr(JSBool allowCallSyntax) ParseNode * Parser::bracketedExpr() { - unsigned oldflags; - ParseNode *pn; - /* * Always accept the 'in' operator in a parenthesized expression, * where it's unambiguous, even if we might be parsing the init of a * for statement. */ - oldflags = tc->sc->flags; - tc->sc->flags &= ~TCF_IN_FOR_INIT; - pn = expr(); + uint32_t oldflags = tc->sc->flags; + bool oldInForInit = tc->sc->inForInit; + tc->sc->inForInit = false; + ParseNode *pn = expr(); tc->sc->flags = oldflags | (tc->sc->flags & TCF_FUN_FLAGS); + tc->sc->inForInit = oldInForInit; return pn; } diff --git a/js/src/frontend/TreeContext-inl.h b/js/src/frontend/TreeContext-inl.h index bc4e083ba32c..eaac8e574685 100644 --- a/js/src/frontend/TreeContext-inl.h +++ b/js/src/frontend/TreeContext-inl.h @@ -64,7 +64,8 @@ SharedContext::SharedContext(JSContext *cx, bool inFunction) functionList(NULL), bindings(cx), bindingsRoot(cx, &bindings), - inFunction(inFunction) + inFunction(inFunction), + inForInit(false) { } diff --git a/js/src/frontend/TreeContext.h b/js/src/frontend/TreeContext.h index cbec0f2a8452..6e3638540c8d 100644 --- a/js/src/frontend/TreeContext.h +++ b/js/src/frontend/TreeContext.h @@ -58,24 +58,21 @@ namespace js { JS_ENUM_HEADER(TreeContextFlags, uint32_t) { - // parsing init expr of for; exclude 'in' - TCF_IN_FOR_INIT = 0x1, - // function needs Call object per call - TCF_FUN_HEAVYWEIGHT = 0x2, + TCF_FUN_HEAVYWEIGHT = 0x1, // parsed yield statement in function - TCF_FUN_IS_GENERATOR = 0x4, + TCF_FUN_IS_GENERATOR = 0x2, // flag lambda from generator expression - TCF_GENEXP_LAMBDA = 0x8, + TCF_GENEXP_LAMBDA = 0x4, // This function/global/eval code body contained a Use Strict Directive. // Treat certain strict warnings as errors, and forbid the use of 'with'. // See also TSF_STRICT_MODE_CODE, JSScript::strictModeCode, and // JSREPORT_STRICT_ERROR. // - TCF_STRICT_MODE_CODE = 0x10, + TCF_STRICT_MODE_CODE = 0x8, // The (static) bindings of this script need to support dynamic name // read/write access. Here, 'dynamic' means dynamic dictionary lookup on @@ -97,17 +94,17 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t) // taken not to turn off the whole 'arguments' optimization). To answer the // more general "is this argument aliased" question, script->needsArgsObj // should be tested (see JSScript::argIsAlised). - TCF_BINDINGS_ACCESSED_DYNAMICALLY = 0x20, + TCF_BINDINGS_ACCESSED_DYNAMICALLY = 0x10, // The function or a function that encloses it may define new local names // at runtime through means other than calling eval. - TCF_FUN_MIGHT_ALIAS_LOCALS = 0x40, + TCF_FUN_MIGHT_ALIAS_LOCALS = 0x20, // The script contains singleton initialiser JSOP_OBJECT. - TCF_HAS_SINGLETONS = 0x80, + TCF_HAS_SINGLETONS = 0x40, // Some enclosing scope is a with-statement or E4X filter-expression. - TCF_IN_WITH = 0x100, + TCF_IN_WITH = 0x80, // This function does something that can extend the set of bindings in its // call objects --- it does a direct eval in non-strict code, or includes a @@ -116,7 +113,7 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t) // This flag is *not* inherited by enclosed or enclosing functions; it // applies only to the function in whose flags it appears. // - TCF_FUN_EXTENSIBLE_SCOPE = 0x200, + TCF_FUN_EXTENSIBLE_SCOPE = 0x100, // Technically, every function has a binding named 'arguments'. Internally, // this binding is only added when 'arguments' is mentioned by the function @@ -139,7 +136,7 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t) // have no special semantics: the initial value is unconditionally the // actual argument (or undefined if nactual < nformal). // - TCF_ARGUMENTS_HAS_LOCAL_BINDING = 0x400, + TCF_ARGUMENTS_HAS_LOCAL_BINDING = 0x200, // In many cases where 'arguments' has a local binding (as described above) // we do not need to actually create an arguments object in the function @@ -150,7 +147,7 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t) // be unsound in several cases. The frontend filters out such cases by // setting this flag which eagerly sets script->needsArgsObj to true. // - TCF_DEFINITELY_NEEDS_ARGS_OBJ = 0x800 + TCF_DEFINITELY_NEEDS_ARGS_OBJ = 0x400 } JS_ENUM_FOOTER(TreeContextFlags); @@ -198,7 +195,9 @@ struct SharedContext { arguments if we're compiling a function */ Bindings::StackRoot bindingsRoot; /* root for stack allocated bindings. */ - const bool inFunction; /* parsing/emitting inside function body */ + const bool inFunction:1; /* parsing/emitting inside function body */ + + bool inForInit:1; /* parsing/emitting init expr of for; exclude 'in' */ inline SharedContext(JSContext *cx, bool inFunction);