Bug 1343481 - Part 7: Add BytecodeEmitter::emitDotGenerator and make yield/await nodes unary.

Tag #1287
This commit is contained in:
Gaming4JC 2019-12-13 20:55:24 -05:00 • committed by Roy Tam
commit c1bdfa62fc
11 changed files with 124 additions and 112 deletions

View file

@ -2800,11 +2800,11 @@ ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst)
LOCAL_ASSERT(next->isKind(PNK_SEMI) && LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
next->pn_kid->isKind(PNK_YIELD) && next->pn_kid->isKind(PNK_YIELD) &&
next->pn_kid->pn_left); next->pn_kid->pn_kid);
RootedValue body(cx); RootedValue body(cx);
return expression(next->pn_kid->pn_left, &body) && return expression(next->pn_kid->pn_kid, &body) &&
builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst); builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
} }
@ -3146,7 +3146,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_YIELD_STAR: case PNK_YIELD_STAR:
{ {
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos)); MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
RootedValue arg(cx); RootedValue arg(cx);
return expression(pn->pn_left, &arg) && return expression(pn->pn_left, &arg) &&
@ -3155,10 +3155,10 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_YIELD: case PNK_YIELD:
{ {
MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos)); MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
RootedValue arg(cx); RootedValue arg(cx);
return optExpression(pn->pn_left, &arg) && return optExpression(pn->pn_kid, &arg) &&
builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst); builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
} }
@ -3480,7 +3480,7 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
ParseNode* pnstart = pnbody->pn_head; ParseNode* pnstart = pnbody->pn_head;
// Skip over initial yield in generator. // Skip over initial yield in generator.
if (pnstart && pnstart->isKind(PNK_YIELD)) { if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) {
MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD); MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
pnstart = pnstart->pn_next; pnstart = pnstart->pn_next;
} }

View file

@ -3175,10 +3175,11 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = true; *answer = true;
return true; return true;
case PNK_INITIALYIELD:
case PNK_YIELD_STAR: case PNK_YIELD_STAR:
case PNK_YIELD: case PNK_YIELD:
case PNK_AWAIT: case PNK_AWAIT:
MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true; *answer = true;
return true; return true;
@ -8526,45 +8527,61 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
} }
bool bool
BytecodeEmitter::emitYield(ParseNode* pn) BytecodeEmitter::emitGetDotGenerator()
{ {
MOZ_ASSERT(sc->isFunctionBox()); NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator);
return emitGetNameAtLocation(cx->names().dotGenerator, loc);
}
if (pn->getOp() == JSOP_YIELD || pn->getOp() == JSOP_AWAIT) { bool
bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult(); BytecodeEmitter::emitInitialYield(ParseNode* pn)
if (needsIteratorResult) { {
if (!emitPrepareIteratorResult()) if (!emitTree(pn->pn_kid))
return false;
}
if (pn->pn_left) {
if (!emitTree(pn->pn_left))
return false;
} else {
if (!emit1(JSOP_UNDEFINED))
return false;
}
if (needsIteratorResult) {
if (!emitFinishIteratorResult(false))
return false;
}
} else {
MOZ_ASSERT(pn->getOp() == JSOP_INITIALYIELD);
}
if (!emitTree(pn->pn_right))
return false; return false;
if (!emitYieldOp(pn->getOp())) if (!emitYieldOp(JSOP_INITIALYIELD))
return false; return false;
if (pn->getOp() == JSOP_INITIALYIELD && !emit1(JSOP_POP)) if (!emit1(JSOP_POP))
return false; return false;
return true; return true;
} }
bool bool
BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen) BytecodeEmitter::emitYield(ParseNode* pn)
{
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(pn->getOp() == JSOP_YIELD || pn->getOp() == JSOP_AWAIT);
bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
if (needsIteratorResult) {
if (!emitPrepareIteratorResult())
return false;
}
if (pn->pn_kid) {
if (!emitTree(pn->pn_kid))
return false;
} else {
if (!emit1(JSOP_UNDEFINED))
return false;
}
if (needsIteratorResult) {
if (!emitFinishIteratorResult(false))
return false;
}
if (!emitGetDotGenerator())
return false;
if (!emitYieldOp(pn->getOp()))
return false;
return true;
}
bool
BytecodeEmitter::emitYieldStar(ParseNode* iter)
{ {
MOZ_ASSERT(sc->isFunctionBox()); MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(sc->asFunctionBox()->isStarGenerator()); MOZ_ASSERT(sc->asFunctionBox()->isStarGenerator());
@ -8594,7 +8611,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
MOZ_ASSERT(this->stackDepth == startDepth); MOZ_ASSERT(this->stackDepth == startDepth);
// Load the generator object. // Load the generator object.
if (!emitTree(gen)) // ITER RESULT GENOBJ if (!emitGetDotGenerator()) // ITER RESULT GENOBJ
return false; return false;
// Yield RESULT as-is, without re-boxing. // Yield RESULT as-is, without re-boxing.
@ -10339,8 +10356,7 @@ BytecodeEmitter::emitFunctionBody(ParseNode* funBody)
if (!emit1(JSOP_SETRVAL)) if (!emit1(JSOP_SETRVAL))
return false; return false;
NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator); if (!emitGetDotGenerator())
if (!emitGetNameAtLocation(cx->names().dotGenerator, loc))
return false; return false;
// No need to check for finally blocks, etc as in EmitReturn. // No need to check for finally blocks, etc as in EmitReturn.
@ -10600,7 +10616,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
break; break;
case PNK_YIELD_STAR: case PNK_YIELD_STAR:
if (!emitYieldStar(pn->pn_left, pn->pn_right)) if (!emitYieldStar(pn->pn_kid))
return false; return false;
break; break;
@ -10609,6 +10625,11 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
return false; return false;
break; break;
case PNK_INITIALYIELD:
if (!emitInitialYield(pn))
return false;
break;
case PNK_YIELD: case PNK_YIELD:
case PNK_AWAIT: case PNK_AWAIT:
if (!emitYield(pn)) if (!emitYield(pn))

View file

@ -607,9 +607,12 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitFinishIteratorResult(bool done); MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
MOZ_MUST_USE bool iteratorResultShape(unsigned* shape); MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
MOZ_MUST_USE bool emitGetDotGenerator();
MOZ_MUST_USE bool emitInitialYield(ParseNode* pn);
MOZ_MUST_USE bool emitYield(ParseNode* pn); MOZ_MUST_USE bool emitYield(ParseNode* pn);
MOZ_MUST_USE bool emitYieldOp(JSOp op); MOZ_MUST_USE bool emitYieldOp(JSOp op);
MOZ_MUST_USE bool emitYieldStar(ParseNode* iter, ParseNode* gen); MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
MOZ_MUST_USE bool emitPropLHS(ParseNode* pn); MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op); MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);

View file

@ -117,9 +117,10 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
// These two aren't statements in the spec, but we sometimes insert them // These two aren't statements in the spec, but we sometimes insert them
// in statement lists anyway. // in statement lists anyway.
case PNK_INITIALYIELD:
case PNK_YIELD_STAR: case PNK_YIELD_STAR:
case PNK_YIELD: case PNK_YIELD:
MOZ_ASSERT(node->isArity(PN_BINARY)); MOZ_ASSERT(node->isArity(PN_UNARY));
*result = false; *result = false;
return true; return true;
@ -1775,21 +1776,23 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_GENEXP: case PNK_GENEXP:
return FoldList(cx, pn, parser, inGenexpLambda); return FoldList(cx, pn, parser, inGenexpLambda);
case PNK_INITIALYIELD:
MOZ_ASSERT(pn->isArity(PN_UNARY));
MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
pn->pn_kid->pn_left->isKind(PNK_NAME) &&
pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
return true;
case PNK_YIELD_STAR: case PNK_YIELD_STAR:
MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->isArity(PN_UNARY));
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME)); return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
case PNK_YIELD: case PNK_YIELD:
case PNK_AWAIT: case PNK_AWAIT:
MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->isArity(PN_UNARY));
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) || if (!pn->pn_kid)
(pn->pn_right->isKind(PNK_ASSIGN) &&
pn->pn_right->pn_left->isKind(PNK_NAME) &&
pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
if (!pn->pn_left)
return true; return true;
return Fold(cx, &pn->pn_left, parser, inGenexpLambda); return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
case PNK_RETURN: case PNK_RETURN:
return FoldReturn(cx, pn, parser, inGenexpLambda); return FoldReturn(cx, pn, parser, inGenexpLambda);

View file

@ -440,20 +440,24 @@ class FullParseHandler
return true; return true;
} }
ParseNode* newYieldExpression(uint32_t begin, ParseNode* value, ParseNode* gen, ParseNode* newInitialYieldExpression(uint32_t begin, ParseNode* gen) {
JSOp op = JSOP_YIELD) { TokenPos pos(begin, begin + 1);
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1); return new_<UnaryNode>(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen);
return new_<BinaryNode>(PNK_YIELD, op, pos, value, gen);
} }
ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value, ParseNode* gen) { ParseNode* newYieldExpression(uint32_t begin, ParseNode* value) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
return new_<UnaryNode>(PNK_YIELD, JSOP_YIELD, pos, value);
}
ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value) {
TokenPos pos(begin, value->pn_pos.end); TokenPos pos(begin, value->pn_pos.end);
return new_<BinaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen); return new_<UnaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value);
} }
ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) { ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1); TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
return new_<BinaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value, gen); return new_<UnaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value);
} }
// Statements // Statements
@ -506,8 +510,7 @@ class FullParseHandler
if (!genInit) if (!genInit)
return false; return false;
ParseNode* initialYield = newYieldExpression(yieldPos.begin, nullptr, genInit, ParseNode* initialYield = newInitialYieldExpression(yieldPos.begin, genInit);
JSOP_INITIALYIELD);
if (!initialYield) if (!initialYield)
return false; return false;

View file

@ -501,24 +501,25 @@ class NameResolver
return false; return false;
break; break;
case PNK_INITIALYIELD:
MOZ_ASSERT(cur->pn_kid->isKind(PNK_ASSIGN) &&
cur->pn_kid->pn_left->isKind(PNK_NAME) &&
cur->pn_kid->pn_right->isKind(PNK_GENERATOR));
break;
case PNK_YIELD_STAR: case PNK_YIELD_STAR:
MOZ_ASSERT(cur->isArity(PN_BINARY)); MOZ_ASSERT(cur->isArity(PN_UNARY));
MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME)); if (!resolve(cur->pn_kid, prefix))
if (!resolve(cur->pn_left, prefix))
return false; return false;
break; break;
case PNK_YIELD: case PNK_YIELD:
case PNK_AWAIT: case PNK_AWAIT:
MOZ_ASSERT(cur->isArity(PN_BINARY)); MOZ_ASSERT(cur->isArity(PN_UNARY));
if (cur->pn_left) { if (cur->pn_kid) {
if (!resolve(cur->pn_left, prefix)) if (!resolve(cur->pn_kid, prefix))
return false; return false;
} }
MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME) ||
(cur->pn_right->isKind(PNK_ASSIGN) &&
cur->pn_right->pn_left->isKind(PNK_NAME) &&
cur->pn_right->pn_right->isKind(PNK_GENERATOR)));
break; break;
case PNK_RETURN: case PNK_RETURN:

View file

@ -286,22 +286,24 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
return PushResult::Recyclable; return PushResult::Recyclable;
} }
// The left half is the expression being yielded. The right half is // The child is an assignment of a PNK_GENERATOR node to the
// internal goop: a name reference to the invisible '.generator' local // '.generator' local, for a synthesized, prepended initial yield.
// variable, or an assignment of a PNK_GENERATOR node to the '.generator' case PNK_INITIALYIELD: {
// local, for a synthesized, prepended initial yield. Yum! MOZ_ASSERT(pn->isArity(PN_UNARY));
MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
pn->pn_kid->pn_left->isKind(PNK_NAME) &&
pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
stack->push(pn->pn_kid);
return PushResult::Recyclable;
}
// The child is the expression being yielded.
case PNK_YIELD_STAR: case PNK_YIELD_STAR:
case PNK_YIELD: case PNK_YIELD:
case PNK_AWAIT: { case PNK_AWAIT: {
MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->isArity(PN_UNARY));
MOZ_ASSERT(pn->pn_right); if (pn->pn_kid)
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) || stack->push(pn->pn_kid);
(pn->pn_right->isKind(PNK_ASSIGN) &&
pn->pn_right->pn_left->isKind(PNK_NAME) &&
pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
if (pn->pn_left)
stack->push(pn->pn_left);
stack->push(pn->pn_right);
return PushResult::Recyclable; return PushResult::Recyclable;
} }

View file

@ -83,6 +83,7 @@ class ObjectBox;
F(THROW) \ F(THROW) \
F(DEBUGGER) \ F(DEBUGGER) \
F(GENERATOR) \ F(GENERATOR) \
F(INITIALYIELD) \
F(YIELD) \ F(YIELD) \
F(YIELD_STAR) \ F(YIELD_STAR) \
F(GENEXP) \ F(GENEXP) \
@ -418,8 +419,9 @@ IsTypeofKind(ParseNodeKind kind)
* PNK_LEXICALSCOPE scope pn_u.scope.bindings: scope bindings * PNK_LEXICALSCOPE scope pn_u.scope.bindings: scope bindings
* pn_u.scope.body: scope body * pn_u.scope.body: scope body
* PNK_GENERATOR nullary * PNK_GENERATOR nullary
* PNK_YIELD, binary pn_left: expr or null; pn_right: generator object * PNK_INITIALYIELD unary pn_kid: generator object
* PNK_YIELD_STAR * PNK_YIELD, unary pn_kid: expr or null
* PNK_YIELD_STAR,
* PNK_ARRAYCOMP list pn_count: 1 * PNK_ARRAYCOMP list pn_count: 1
* pn_head: list of 1 element, which is block * pn_head: list of 1 element, which is block
* enclosing for loop(s) and optionally * enclosing for loop(s) and optionally

View file

@ -6546,29 +6546,6 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
return pn; return pn;
} }
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr,
bool isYieldStar)
{
Node generator = newDotGeneratorName();
if (!generator)
return null();
if (isYieldStar)
return handler.newYieldStarExpression(begin, expr, generator);
return handler.newYieldExpression(begin, expr, generator);
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::newAwaitExpression(uint32_t begin, typename ParseHandler::Node expr)
{
Node generator = newDotGeneratorName();
if (!generator)
return null();
return handler.newAwaitExpression(begin, expr, generator);
}
template <typename ParseHandler> template <typename ParseHandler>
typename ParseHandler::Node typename ParseHandler::Node
Parser<ParseHandler>::yieldExpression(InHandling inHandling) Parser<ParseHandler>::yieldExpression(InHandling inHandling)
@ -6617,7 +6594,9 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
if (!exprNode) if (!exprNode)
return null(); return null();
} }
return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR); if (kind == PNK_YIELD_STAR)
return handler.newYieldStarExpression(begin, exprNode);
return handler.newYieldExpression(begin, exprNode);
} }
case NotGenerator: case NotGenerator:
@ -6694,7 +6673,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
return null(); return null();
} }
return newYieldExpression(begin, exprNode); return handler.newYieldExpression(begin, exprNode);
} }
} }
@ -8449,7 +8428,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
if (!kid) if (!kid)
return null(); return null();
pc->lastAwaitOffset = begin; pc->lastAwaitOffset = begin;
return newAwaitExpression(begin, kid); return handler.newAwaitExpression(begin, kid);
} }
} }
@ -8707,7 +8686,7 @@ Parser<ParseHandler>::comprehensionTail(GeneratorKind comprehensionKind)
return handler.newArrayPush(begin, bodyExpr); return handler.newArrayPush(begin, bodyExpr);
MOZ_ASSERT(comprehensionKind == StarGenerator); MOZ_ASSERT(comprehensionKind == StarGenerator);
Node yieldExpr = newYieldExpression(begin, bodyExpr); Node yieldExpr = handler.newYieldExpression(begin, bodyExpr);
if (!yieldExpr) if (!yieldExpr)
return null(); return null();
yieldExpr = handler.parenthesize(yieldExpr); yieldExpr = handler.parenthesize(yieldExpr);

View file

@ -1110,8 +1110,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
inline Node newName(PropertyName* name); inline Node newName(PropertyName* name);
inline Node newName(PropertyName* name, TokenPos pos); inline Node newName(PropertyName* name, TokenPos pos);
inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
inline Node newAwaitExpression(uint32_t begin, Node expr);
inline bool abortIfSyntaxParser(); inline bool abortIfSyntaxParser();

View file

@ -301,9 +301,9 @@ class SyntaxParseHandler
MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; } MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; }
MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } Node newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } Node newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
Node newAwaitExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } Node newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; }
// Statements // Statements