diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 29c38c15378..cbcbba59951 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -83,7 +83,8 @@ BytecodeEmitter::BytecodeEmitter(Parser *parser, SharedContext *sc, unsigned lin typesetCount(0), noScriptRval(noScriptRval), needScriptGlobal(needScriptGlobal), - hasSingletons(false) + hasSingletons(false), + inForInit(false) { memset(&prolog, 0, sizeof prolog); memset(&main, 0, sizeof main); @@ -1220,7 +1221,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->inForInit) + if (bce->inForInit) return JS_TRUE; JS_ASSERT(caller->isScriptFrame()); @@ -1653,11 +1654,11 @@ EmitXMLName(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME); ParseNode *pn2 = pn->pn_kid; - bool oldInForInit = bce->sc->inForInit; - bce->sc->inForInit = false; + bool oldInForInit = bce->inForInit; + bce->inForInit = false; if (!EmitTree(cx, bce, pn2)) return false; - bce->sc->inForInit = oldInForInit; + bce->inForInit = oldInForInit; if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pn2->pn_offset) < 0) return false; @@ -3346,11 +3347,11 @@ EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption return JS_FALSE; } - bool oldInForInit = bce->sc->inForInit; - bce->sc->inForInit = false; + bool oldInForInit = bce->inForInit; + bce->inForInit = false; if (!EmitTree(cx, bce, pn3)) return JS_FALSE; - bce->sc->inForInit = oldInForInit; + bce->inForInit = oldInForInit; } else if (letNotes) { /* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */ if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) @@ -4499,10 +4500,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->inForInit = true; + bce->inForInit = true; if (!EmitVariables(cx, bce, decl, DefineVars)) return false; - bce->sc->inForInit = false; + bce->inForInit = false; } /* Compile the object expression to the right of 'in'. */ @@ -4642,7 +4643,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->inForInit = true; + bce->inForInit = true; #if JS_HAS_DESTRUCTURING if (pn3->isKind(PNK_ASSIGN)) { JS_ASSERT(pn3->isOp(JSOP_NOP)); @@ -4665,7 +4666,7 @@ EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) op = JSOP_NOP; } } - bce->sc->inForInit = false; + bce->inForInit = false; } /* @@ -5327,13 +5328,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. */ - bool oldInForInit = bce->sc->inForInit; - bce->sc->inForInit = false; + bool oldInForInit = bce->inForInit; + bce->inForInit = false; for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) { if (!EmitTree(cx, bce, pn3)) return false; } - bce->sc->inForInit = oldInForInit; + bce->inForInit = oldInForInit; if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - off) < 0) return false; @@ -5813,12 +5814,12 @@ EmitUnary(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (op == JSOP_TYPEOF && !pn2->isKind(PNK_NAME)) op = JSOP_TYPEOFEXPR; - bool oldInForInit = bce->sc->inForInit; - bce->sc->inForInit = false; + bool oldInForInit = bce->inForInit; + bce->inForInit = false; if (!EmitTree(cx, bce, pn2)) return false; - bce->sc->inForInit = oldInForInit; + bce->inForInit = oldInForInit; return Emit1(cx, bce, op) >= 0; } @@ -6220,8 +6221,8 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) * possibly including a let (a = b) ... expression. We must clear * inForInit to avoid mis-compiling such beasts. */ - bool oldInForInit = bce->sc->inForInit; - bce->sc->inForInit = false; + bool oldInForInit = bce->inForInit; + bce->inForInit = false; #endif /* Binary operators that evaluate both operands unconditionally. */ @@ -6230,7 +6231,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->inForInit = oldInForInit; + bce->inForInit = oldInForInit; #endif if (Emit1(cx, bce, pn->getOp()) < 0) return JS_FALSE; @@ -6245,11 +6246,11 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) } else { JSOp op = pn->getOp(); JS_ASSERT(op == JSOP_BINDXMLNAME || op == JSOP_SETXMLNAME); - bool oldInForInit = bce->sc->inForInit; - bce->sc->inForInit = false; + bool oldInForInit = bce->inForInit; + bce->inForInit = false; if (!EmitTree(cx, bce, pn->pn_kid)) return false; - bce->sc->inForInit = oldInForInit; + bce->inForInit = oldInForInit; if (Emit1(cx, bce, op) < 0) return false; } diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index de12b7d83b6..4b54d85409a 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -127,6 +127,8 @@ struct BytecodeEmitter bool hasSingletons:1; /* script contains singleton initializer JSOP_OBJECT */ + bool inForInit:1; /* emitting init expr of for; exclude 'in' */ + BytecodeEmitter(Parser *parser, SharedContext *sc, unsigned lineno, bool noScriptRval, bool needScriptGlobal); bool init(); diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f52a15ed5dc..31d132758ec 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3151,7 +3151,7 @@ Parser::forStatement() * expressions involving an 'in' operator are illegal in the init * clause of an ordinary for loop. */ - tc->sc->inForInit = true; + tc->inForInit = true; if (tt == TOK_VAR || tt == TOK_CONST) { forDecl = true; tokenStream.consumeKnownToken(tt); @@ -3174,7 +3174,7 @@ Parser::forStatement() else { pn1 = expr(); } - tc->sc->inForInit = false; + tc->inForInit = false; if (!pn1) return NULL; } @@ -3192,7 +3192,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 - * tc->sc->inForInit. + * tc->inForInit. */ ParseNode *forHead; /* initialized by both branches. */ StmtInfo letStmt(context); /* used if blockObj != NULL. */ @@ -4255,7 +4255,7 @@ Parser::variables(ParseNodeKind kind, StaticBlockObject *blockObj, VarContext va if (!CheckDestructuring(context, &data, pn2, this)) return NULL; bool ignored; - if (tc->sc->inForInit && matchInOrOf(&ignored)) { + if (tc->inForInit && matchInOrOf(&ignored)) { tokenStream.ungetToken(); pn->append(pn2); continue; @@ -4462,8 +4462,8 @@ BEGIN_EXPR_PARSER(relExpr1) * Uses of the in operator in shiftExprs are always unambiguous, * so unset the flag that prohibits recognizing it. */ - bool oldInForInit = tc->sc->inForInit; - tc->sc->inForInit = false; + bool oldInForInit = tc->inForInit; + tc->inForInit = false; ParseNode *pn = shiftExpr1i(); while (pn && @@ -4479,7 +4479,7 @@ BEGIN_EXPR_PARSER(relExpr1) pn = ParseNode::newBinaryOrAppend(kind, op, pn, shiftExpr1n(), this); } /* Restore previous state of inForInit flag. */ - tc->sc->inForInit |= oldInForInit; + tc->inForInit |= oldInForInit; return pn; } @@ -4573,10 +4573,10 @@ Parser::condExpr1() * where it's unambiguous, even if we might be parsing the init of a * for statement. */ - bool oldInForInit = tc->sc->inForInit; - tc->sc->inForInit = false; + bool oldInForInit = tc->inForInit; + tc->inForInit = false; ParseNode *thenExpr = assignExpr(); - tc->sc->inForInit = oldInForInit; + tc->inForInit = oldInForInit; if (!thenExpr) return NULL; @@ -5874,10 +5874,10 @@ Parser::bracketedExpr() * where it's unambiguous, even if we might be parsing the init of a * for statement. */ - bool oldInForInit = tc->sc->inForInit; - tc->sc->inForInit = false; + bool oldInForInit = tc->inForInit; + tc->inForInit = false; ParseNode *pn = expr(); - tc->sc->inForInit = oldInForInit; + tc->inForInit = oldInForInit; return pn; } diff --git a/js/src/frontend/TreeContext-inl.h b/js/src/frontend/TreeContext-inl.h index 1d14e740910..c3f7f392bd6 100644 --- a/js/src/frontend/TreeContext-inl.h +++ b/js/src/frontend/TreeContext-inl.h @@ -30,7 +30,6 @@ SharedContext::SharedContext(JSContext *cx, JSObject *scopeChain, JSFunction *fu staticLevel(0), bindings(cx), bindingsRoot(cx, &bindings), - inForInit(false), cxFlags(cx) { JS_ASSERT((fun && !scopeChain_) || (!fun && !funbox)); @@ -78,6 +77,7 @@ TreeContext::TreeContext(Parser *prs, SharedContext *sc) funcStmts(NULL), hasReturnExpr(false), hasReturnVoid(false), + inForInit(false), inDeclDestructuring(false) { prs->tc = this; diff --git a/js/src/frontend/TreeContext.h b/js/src/frontend/TreeContext.h index f476978d208..e38970e9dba 100644 --- a/js/src/frontend/TreeContext.h +++ b/js/src/frontend/TreeContext.h @@ -156,8 +156,6 @@ struct SharedContext { arguments if we're compiling a function */ Bindings::AutoRooter bindingsRoot; /* root for stack allocated bindings. */ - bool inForInit:1; /* parsing/emitting init expr of for; exclude 'in' */ - ContextFlags cxFlags; // If it's function code, fun must be non-NULL and scopeChain must be NULL. @@ -256,6 +254,8 @@ struct TreeContext { /* tree context for semantic checks */ bool hasReturnExpr:1; /* function has 'return ;' */ bool hasReturnVoid:1; /* function has 'return;' */ + bool inForInit:1; /* parsing init expr of for; exclude 'in' */ + // Set when parsing a declaration-like destructuring pattern. This flag // causes PrimaryExpr to create PN_NAME parse nodes for variable references // which are not hooked into any definition's use chain, added to any tree