Bug 1227677 - Extract PNK_COMPREHENSIONFOR from PNK_FOR so that comprehension gunk doesn't taint for-loop emitting logic. r=shu

This commit is contained in:
Jeff Walden 2015-11-24 11:00:43 -08:00
parent 4560db90e5
commit f5da2608e0
10 changed files with 65 additions and 29 deletions

View File

@ -2495,6 +2495,7 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
}
case PNK_FOR:
case PNK_COMPREHENSIONFOR:
{
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
@ -2759,12 +2760,12 @@ ASTSerializer::comprehension(ParseNode* pn, MutableHandleValue dst)
// They have slightly different parse trees and scoping.
bool isLegacy = pn->isKind(PNK_LEXICALSCOPE);
ParseNode* next = isLegacy ? pn->pn_expr : pn;
LOCAL_ASSERT(next->isKind(PNK_FOR));
LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR));
NodeVector blocks(cx);
RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
while (true) {
if (next->isKind(PNK_FOR)) {
if (next->isKind(PNK_COMPREHENSIONFOR)) {
RootedValue block(cx);
if (!comprehensionBlock(next, &block) || !blocks.append(block))
return false;
@ -2802,12 +2803,12 @@ ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst)
// expression.
bool isLegacy = pn->isKind(PNK_LEXICALSCOPE);
ParseNode* next = isLegacy ? pn->pn_expr : pn;
LOCAL_ASSERT(next->isKind(PNK_FOR));
LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR));
NodeVector blocks(cx);
RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
while (true) {
if (next->isKind(PNK_FOR)) {
if (next->isKind(PNK_COMPREHENSIONFOR)) {
RootedValue block(cx);
if (!comprehensionBlock(next, &block) || !blocks.append(block))
return false;

View File

@ -2189,6 +2189,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_DOWHILE:
case PNK_WHILE:
case PNK_FOR:
case PNK_COMPREHENSIONFOR:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
@ -2347,9 +2348,9 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = true;
return true;
case PNK_FORIN: // by PNK_FOR
case PNK_FOROF: // by PNK_FOR
case PNK_FORHEAD: // by PNK_FOR
case PNK_FORIN: // by PNK_FOR/PNK_COMPREHENSIONFOR
case PNK_FOROF: // by PNK_FOR/PNK_COMPREHENSIONFOR
case PNK_FORHEAD: // by PNK_FOR/PNK_COMPREHENSIONFOR
case PNK_CLASSMETHOD: // by PNK_CLASS
case PNK_CLASSNAMES: // by PNK_CLASS
case PNK_CLASSMETHODLIST: // by PNK_CLASS
@ -5425,8 +5426,14 @@ bool
BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn)
{
MOZ_ASSERT(type == StmtType::FOR_OF_LOOP || type == StmtType::SPREAD);
MOZ_ASSERT_IF(type == StmtType::FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
MOZ_ASSERT_IF(type == StmtType::SPREAD, !pn);
#ifdef DEBUG
if (type == StmtType::FOR_OF_LOOP) {
MOZ_ASSERT(pn);
MOZ_ASSERT(pn->pn_left->isKind(PNK_FOROF));
} else {
MOZ_ASSERT(!pn);
}
#endif
ptrdiff_t top = offset();
ParseNode* forHead = pn ? pn->pn_left : nullptr;
@ -7974,6 +7981,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
break;
case PNK_FOR:
case PNK_COMPREHENSIONFOR:
if (!emitFor(pn))
return false;
break;

View File

@ -627,7 +627,8 @@ struct BytecodeEmitter
bool emitSpread();
// If type is StmtType::FOR_OF_LOOP, emit bytecode for a for-of loop.
// pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
// pn should be PNK_FOR or PNK_COMPREHENSIONFOR, and pn->pn_left should be
// PNK_FOROF.
//
// If type is StmtType::SPREAD, emit bytecode for spread operator.
// pn should be nullptr.

View File

@ -241,7 +241,8 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_CASE:
return ContainsHoistedDeclaration(cx, node->as<CaseClause>().statementList(), result);
case PNK_FOR: {
case PNK_FOR:
case PNK_COMPREHENSIONFOR: {
MOZ_ASSERT(node->isArity(PN_BINARY));
ParseNode* loopHead = node->pn_left;
@ -1890,6 +1891,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_SHORTHAND:
case PNK_LETBLOCK:
case PNK_FOR:
case PNK_COMPREHENSIONFOR:
case PNK_CLASSMETHOD:
case PNK_IMPORT_SPEC:
case PNK_EXPORT_SPEC:

View File

@ -565,6 +565,19 @@ class FullParseHandler
return pn;
}
ParseNode* newComprehensionFor(uint32_t begin, ParseNode* forHead, ParseNode* body) {
// A PNK_COMPREHENSIONFOR node is binary: left is loop control, right
// is the body.
MOZ_ASSERT(forHead->isKind(PNK_FORIN) || forHead->isKind(PNK_FOROF));
JSOp op = forHead->isKind(PNK_FORIN) ? JSOP_ITER : JSOP_NOP;
BinaryNode* pn = new_<BinaryNode>(PNK_COMPREHENSIONFOR, op,
TokenPos(begin, body->pn_pos.end), forHead, body);
if (!pn)
return null();
pn->pn_iflags = JSOP_ITER;
return pn;
}
ParseNode* newForHead(ParseNodeKind kind, ParseNode* pn1, ParseNode* pn2, ParseNode* pn3,
const TokenPos& pos)
{

View File

@ -448,6 +448,7 @@ class NameResolver
case PNK_SWITCH:
case PNK_LETBLOCK:
case PNK_FOR:
case PNK_COMPREHENSIONFOR:
case PNK_CLASSMETHOD:
case PNK_SETTHIS:
MOZ_ASSERT(cur->isArity(PN_BINARY));
@ -687,13 +688,15 @@ class NameResolver
}
break;
// Array comprehension nodes are lists with a single child -- PNK_FOR for
// comprehensions, PNK_LEXICALSCOPE for legacy comprehensions. Probably
// this should be a non-list eventually.
// Array comprehension nodes are lists with a single child:
// PNK_COMPREHENSIONFOR for comprehensions, PNK_LEXICALSCOPE for
// legacy comprehensions. Probably this should be a non-list
// eventually.
case PNK_ARRAYCOMP:
MOZ_ASSERT(cur->isArity(PN_LIST));
MOZ_ASSERT(cur->pn_count == 1);
MOZ_ASSERT(cur->pn_head->isKind(PNK_LEXICALSCOPE) || cur->pn_head->isKind(PNK_FOR));
MOZ_ASSERT(cur->pn_head->isKind(PNK_LEXICALSCOPE) ||
cur->pn_head->isKind(PNK_COMPREHENSIONFOR));
if (!resolve(cur->pn_head, prefix))
return false;
break;

View File

@ -282,7 +282,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_CLASSMETHOD:
case PNK_NEWTARGET:
case PNK_SETTHIS:
case PNK_FOR: {
case PNK_FOR:
case PNK_COMPREHENSIONFOR: {
MOZ_ASSERT(pn->isArity(PN_BINARY));
stack->push(pn->pn_left);
stack->push(pn->pn_right);
@ -493,15 +494,16 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_CLASSMETHODLIST:
return PushListNodeChildren(pn, stack);
// Array comprehension nodes are lists with a single child -- PNK_FOR for
// comprehensions, PNK_LEXICALSCOPE for legacy comprehensions. Probably
// this should be a non-list eventually.
// Array comprehension nodes are lists with a single child:
// PNK_COMPREHENSIONFOR for comprehensions, PNK_LEXICALSCOPE for legacy
// comprehensions. Probably this should be a non-list eventually.
case PNK_ARRAYCOMP: {
#ifdef DEBUG
MOZ_ASSERT(pn->isKind(PNK_ARRAYCOMP));
MOZ_ASSERT(pn->isArity(PN_LIST));
MOZ_ASSERT(pn->pn_count == 1);
MOZ_ASSERT(pn->pn_head->isKind(PNK_LEXICALSCOPE) || pn->pn_head->isKind(PNK_FOR));
MOZ_ASSERT(pn->pn_head->isKind(PNK_LEXICALSCOPE) ||
pn->pn_head->isKind(PNK_COMPREHENSIONFOR));
#endif
return PushListNodeChildren(pn, stack);
}

View File

@ -126,6 +126,7 @@ class PackedScopeCoordinate
F(WHILE) \
F(DOWHILE) \
F(FOR) \
F(COMPREHENSIONFOR) \
F(BREAK) \
F(CONTINUE) \
F(VAR) \
@ -312,6 +313,8 @@ IsDeleteKind(ParseNodeKind kind)
* PNK_FOR binary pn_left: either PNK_FORIN (for-in statement),
* PNK_FOROF (for-of) or PNK_FORHEAD (for(;;))
* pn_right: body
* PNK_COMPREHENSIONFOR pn_left: either PNK_FORIN or PNK_FOROF
* binary pn_right: body
* PNK_FORIN ternary pn_kid1: PNK_VAR to left of 'in', or nullptr
* pn_kid2: PNK_NAME or destructuring expr
* to left of 'in'; if pn_kid1, then this
@ -619,7 +622,7 @@ class ParseNode
ParseNode* left;
ParseNode* right;
union {
unsigned iflags; /* JSITER_* flags for PNK_FOR node */
unsigned iflags; /* JSITER_* flags for PNK_{COMPREHENSION,}FOR node */
ObjectBox* objbox; /* only for PN_BINARY_OBJ */
bool isStatic; /* only for PNK_CLASSMETHOD */
uint32_t offset; /* for the emitter's use on PNK_CASE nodes */
@ -836,7 +839,8 @@ class ParseNode
ParseNode* callee = this->pn_head;
ParseNode* body = callee->pn_body;
MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
MOZ_ASSERT(body->last()->isKind(PNK_LEXICALSCOPE) || body->last()->isKind(PNK_FOR));
MOZ_ASSERT(body->last()->isKind(PNK_LEXICALSCOPE) ||
body->last()->isKind(PNK_COMPREHENSIONFOR));
return body->last();
}
#endif

View File

@ -7903,12 +7903,10 @@ Parser<FullParseHandler>::legacyComprehensionTail(ParseNode* bodyExpr, unsigned
JSMSG_ARRAY_INIT_TOO_BIG);
while (true) {
/*
* FOR node is binary, left is loop control and right is body. Use
* index to count each block-local let-variable on the left-hand side
* of the in/of.
*/
ParseNode* pn2 = handler.new_<BinaryNode>(PNK_FOR, JSOP_ITER, pos(),
// PNK_COMPREHENSIONFOR is binary: left is loop control, right is body.
// Use index to count each block-local let-variable on the left-hand
// side of the in/of.
ParseNode* pn2 = handler.new_<BinaryNode>(PNK_COMPREHENSIONFOR, JSOP_ITER, pos(),
nullptr, nullptr);
if (!pn2)
return null();
@ -8357,7 +8355,7 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
if (!tail)
return null();
return handler.newForStatement(begin, head, tail, JSOP_ITER);
return handler.newComprehensionFor(begin, head, tail);
}
template <typename ParseHandler>

View File

@ -339,6 +339,10 @@ class SyntaxParseHandler
return NodeGeneric;
}
Node newComprehensionFor(uint32_t begin, Node forHead, Node body) {
return NodeGeneric;
}
Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos& pos) {
return NodeGeneric;
}