Bug 1331092 - Part 9: Implement for-await-of.

Tag #1287
This commit is contained in:
Gaming4JC 2019-12-14 09:22:48 -05:00 committed by Roy Tam
commit 9379133c2d
6 changed files with 59 additions and 11 deletions

View file

@ -2029,12 +2029,16 @@ class ForOfLoopControl : public LoopControl
bool allowSelfHosted_;
IteratorKind iterKind_;
public:
ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted)
ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
IteratorKind iterKind)
: LoopControl(bce, StatementKind::ForOfLoop),
iterDepth_(iterDepth),
numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
allowSelfHosted_(allowSelfHosted)
allowSelfHosted_(allowSelfHosted),
iterKind_(iterKind)
{
}
@ -2118,7 +2122,7 @@ class ForOfLoopControl : public LoopControl
bool emitIteratorClose(BytecodeEmitter* bce,
CompletionKind completionKind = CompletionKind::Normal) {
ptrdiff_t start = bce->offset();
if (!bce->emitIteratorClose(IteratorKind::Sync, completionKind, allowSelfHosted_))
if (!bce->emitIteratorClose(iterKind_, completionKind, allowSelfHosted_))
return false;
ptrdiff_t end = bce->offset();
return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
@ -5246,7 +5250,8 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri
}
bool
BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted /* = false */)
BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = IteratorKind::Sync */,
bool allowSelfHosted /* = false */)
{
MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
".next() iteration is prohibited in self-hosted code because it "
@ -5260,6 +5265,12 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted /* = false
return false;
if (!emitCall(JSOP_CALL, 0, pn)) // ... RESULT
return false;
if (iterKind == IteratorKind::Async) {
if (!emitAwait()) // ... RESULT
return false;
}
if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT
return false;
checkTypeSet(JSOP_CALL);
@ -7099,7 +7110,7 @@ BytecodeEmitter::emitSpread(bool allowSelfHosted)
if (!emitDupAt(2)) // ITER ARR I ITER
return false;
if (!emitIteratorNext(nullptr, allowSelfHosted)) // ITER ARR I RESULT
if (!emitIteratorNext(nullptr, IteratorKind::Sync, allowSelfHosted)) // ITER ARR I RESULT
return false;
if (!emit1(JSOP_DUP)) // ITER ARR I RESULT RESULT
return false;
@ -7199,6 +7210,13 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
MOZ_ASSERT(forOfHead->isKind(PNK_FOROF));
MOZ_ASSERT(forOfHead->isArity(PN_TERNARY));
unsigned iflags = forOfLoop->pn_iflags;
IteratorKind iterKind = (iflags & JSITER_FORAWAITOF)
? IteratorKind::Async
: IteratorKind::Sync;
MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox());
MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox()->isAsync());
ParseNode* forHeadExpr = forOfHead->pn_kid3;
// Certain builtins (e.g. Array.from) are implemented in self-hosting
@ -7214,8 +7232,13 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
// Evaluate the expression being iterated.
if (!emitTree(forHeadExpr)) // ITERABLE
return false;
if (!emitIterator()) // ITER
return false;
if (iterKind == IteratorKind::Async) {
if (!emitAsyncIterator()) // ITER
return false;
} else {
if (!emitIterator()) // ITER
return false;
}
int32_t iterDepth = stackDepth;
@ -7226,7 +7249,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT UNDEF
return false;
ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter);
ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter, iterKind);
// Annotate so IonMonkey can find the loop-closing jump.
unsigned noteIndex;
@ -7322,7 +7345,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
if (!emitDupAt(1)) // ITER UNDEF ITER
return false;
if (!emitIteratorNext(forOfHead, allowSelfHostedIter)) // ITER UNDEF RESULT
if (!emitIteratorNext(forOfHead, iterKind, allowSelfHostedIter)) // ITER UNDEF RESULT
return false;
if (!emit1(JSOP_SWAP)) // ITER RESULT UNDEF

View file

@ -715,7 +715,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter
// Pops iterator from the top of the stack. Pushes the result of |.next()|
// onto the stack.
MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, bool allowSelfHosted = false);
MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
bool allowSelfHosted = false);
MOZ_MUST_USE bool emitIteratorClose(IteratorKind iterKind = IteratorKind::Sync,
CompletionKind completionKind = CompletionKind::Normal,
bool allowSelfHosted = false);

View file

@ -5972,6 +5972,7 @@ Parser<ParseHandler>::matchInOrOf(bool* isForInp, bool* isForOfp)
template <class ParseHandler>
bool
Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
IteratorKind iterKind,
ParseNodeKind* forHeadKind,
Node* forInitialPart,
Maybe<ParseContext::Scope>& forLoopLexicalScope,
@ -6062,6 +6063,11 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
if (!matchInOrOf(&isForIn, &isForOf))
return false;
if (iterKind == IteratorKind::Async && !isForOf) {
error(JSMSG_FOR_AWAIT_NOT_OF);
return false;
}
// If we don't encounter 'in'/'of', we have a for(;;) loop. We've handled
// the init expression; the caller handles the rest. Allow the Operand
// modifier when regetting: Operand must be used to examine the ';' in
@ -6135,6 +6141,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
ParseContext::Statement stmt(pc, StatementKind::ForLoop);
bool isForEach = false;
IteratorKind iterKind = IteratorKind::Sync;
unsigned iflags = 0;
if (allowsForEachIn()) {
@ -6149,6 +6156,19 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
}
}
#ifndef RELEASE_OR_BETA
if (pc->isAsync()) {
bool matched;
if (!tokenStream.matchToken(&matched, TOK_AWAIT))
return null();
if (matched) {
iflags |= JSITER_FORAWAITOF;
iterKind = IteratorKind::Async;
}
}
#endif
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
// PNK_FORHEAD, PNK_FORIN, or PNK_FOROF depending on the loop type.
@ -6186,7 +6206,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
//
// In either case the subsequent token can be consistently accessed using
// TokenStream::None semantics.
if (!forHeadStart(yieldHandling, &headKind, &startNode, forLoopLexicalScope,
if (!forHeadStart(yieldHandling, iterKind, &headKind, &startNode, forLoopLexicalScope,
&iteratedExpr))
{
return null();

View file

@ -12,6 +12,7 @@
#include "mozilla/Array.h"
#include "mozilla/Maybe.h"
#include "jsiter.h"
#include "jspubtd.h"
#include "frontend/BytecodeCompiler.h"
@ -1196,6 +1197,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
Node forStatement(YieldHandling yieldHandling);
bool forHeadStart(YieldHandling yieldHandling,
IteratorKind iterKind,
ParseNodeKind* forHeadKind,
Node* forInitialPart,
mozilla::Maybe<ParseContext::Scope>& forLetImpliedScope,

View file

@ -595,6 +595,7 @@ MSG_DEF(JSMSG_RETURN_NOT_CALLABLE, 0, JSEXN_TYPEERR, "property 'return' of i
MSG_DEF(JSMSG_ITERATOR_NO_THROW, 0, JSEXN_TYPEERR, "iterator does not have a 'throw' method")
// Async Iteration
MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_TYPEERR, "'for await' loop should be used with 'of'")
MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator")
MSG_DEF(JSMSG_NOT_AN_ASYNC_ITERATOR, 0, JSEXN_TYPEERR, "Not an async from sync iterator")
MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value")

View file

@ -948,6 +948,7 @@ IsObjectInContextCompartment(JSObject* obj, const JSContext* cx);
#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */
#define JSITER_SYMBOLS 0x20 /* also include symbol property keys */
#define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */
#define JSITER_FORAWAITOF 0x80 /* for-await-of */
JS_FRIEND_API(bool)
RunningWithTrustedPrincipals(JSContext* cx);