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) &&
next->pn_kid->isKind(PNK_YIELD) &&
next->pn_kid->pn_left);
next->pn_kid->pn_kid);
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);
}
@ -3146,7 +3146,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
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);
return expression(pn->pn_left, &arg) &&
@ -3155,10 +3155,10 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
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);
return optExpression(pn->pn_left, &arg) &&
return optExpression(pn->pn_kid, &arg) &&
builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
}
@ -3480,7 +3480,7 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
ParseNode* pnstart = pnbody->pn_head;
// Skip over initial yield in generator.
if (pnstart && pnstart->isKind(PNK_YIELD)) {
if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) {
MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
pnstart = pnstart->pn_next;
}

View file

@ -3175,10 +3175,11 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = true;
return true;
case PNK_INITIALYIELD:
case PNK_YIELD_STAR:
case PNK_YIELD:
case PNK_AWAIT:
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
@ -8526,45 +8527,61 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
}
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 needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
if (needsIteratorResult) {
if (!emitPrepareIteratorResult())
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))
bool
BytecodeEmitter::emitInitialYield(ParseNode* pn)
{
if (!emitTree(pn->pn_kid))
return false;
if (!emitYieldOp(pn->getOp()))
if (!emitYieldOp(JSOP_INITIALYIELD))
return false;
if (pn->getOp() == JSOP_INITIALYIELD && !emit1(JSOP_POP))
if (!emit1(JSOP_POP))
return false;
return true;
}
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->asFunctionBox()->isStarGenerator());
@ -8594,7 +8611,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
MOZ_ASSERT(this->stackDepth == startDepth);
// Load the generator object.
if (!emitTree(gen)) // ITER RESULT GENOBJ
if (!emitGetDotGenerator()) // ITER RESULT GENOBJ
return false;
// Yield RESULT as-is, without re-boxing.
@ -10339,8 +10356,7 @@ BytecodeEmitter::emitFunctionBody(ParseNode* funBody)
if (!emit1(JSOP_SETRVAL))
return false;
NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator);
if (!emitGetNameAtLocation(cx->names().dotGenerator, loc))
if (!emitGetDotGenerator())
return false;
// No need to check for finally blocks, etc as in EmitReturn.
@ -10600,7 +10616,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
break;
case PNK_YIELD_STAR:
if (!emitYieldStar(pn->pn_left, pn->pn_right))
if (!emitYieldStar(pn->pn_kid))
return false;
break;
@ -10609,6 +10625,11 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
return false;
break;
case PNK_INITIALYIELD:
if (!emitInitialYield(pn))
return false;
break;
case PNK_YIELD:
case PNK_AWAIT:
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 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 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 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
// in statement lists anyway.
case PNK_INITIALYIELD:
case PNK_YIELD_STAR:
case PNK_YIELD:
MOZ_ASSERT(node->isArity(PN_BINARY));
MOZ_ASSERT(node->isArity(PN_UNARY));
*result = false;
return true;
@ -1775,21 +1776,23 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_GENEXP:
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:
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME));
return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
MOZ_ASSERT(pn->isArity(PN_UNARY));
return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
case PNK_YIELD:
case PNK_AWAIT:
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||
(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)
MOZ_ASSERT(pn->isArity(PN_UNARY));
if (!pn->pn_kid)
return true;
return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
case PNK_RETURN:
return FoldReturn(cx, pn, parser, inGenexpLambda);

View file

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

View file

@ -501,24 +501,25 @@ class NameResolver
return false;
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:
MOZ_ASSERT(cur->isArity(PN_BINARY));
MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME));
if (!resolve(cur->pn_left, prefix))
MOZ_ASSERT(cur->isArity(PN_UNARY));
if (!resolve(cur->pn_kid, prefix))
return false;
break;
case PNK_YIELD:
case PNK_AWAIT:
MOZ_ASSERT(cur->isArity(PN_BINARY));
if (cur->pn_left) {
if (!resolve(cur->pn_left, prefix))
MOZ_ASSERT(cur->isArity(PN_UNARY));
if (cur->pn_kid) {
if (!resolve(cur->pn_kid, prefix))
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;
case PNK_RETURN:

View file

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

View file

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

View file

@ -6546,29 +6546,6 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
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>
typename ParseHandler::Node
Parser<ParseHandler>::yieldExpression(InHandling inHandling)
@ -6617,7 +6594,9 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
if (!exprNode)
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:
@ -6694,7 +6673,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
return null();
}
return newYieldExpression(begin, exprNode);
return handler.newYieldExpression(begin, exprNode);
}
}
@ -8449,7 +8428,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
if (!kid)
return null();
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);
MOZ_ASSERT(comprehensionKind == StarGenerator);
Node yieldExpr = newYieldExpression(begin, bodyExpr);
Node yieldExpr = handler.newYieldExpression(begin, bodyExpr);
if (!yieldExpr)
return null();
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, TokenPos pos);
inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
inline Node newAwaitExpression(uint32_t begin, Node expr);
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 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; }
Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
Node newAwaitExpression(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) { return NodeGeneric; }
Node newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; }
// Statements