зеркало из https://github.com/mozilla/gecko-dev.git
Bug 753249 (part 2) - Remove TCF_IN_FOR_INIT from TreeContextFlags. r=luke.
--HG-- extra : rebase_source : f70060e47de0130c558c798a572d83c9184f82c5
This commit is contained in:
Родитель
48cdc0227e
Коммит
1c5be94e4d
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ SharedContext::SharedContext(JSContext *cx, bool inFunction)
|
|||
functionList(NULL),
|
||||
bindings(cx),
|
||||
bindingsRoot(cx, &bindings),
|
||||
inFunction(inFunction)
|
||||
inFunction(inFunction),
|
||||
inForInit(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче