summaryrefslogtreecommitdiffstats
path: root/js/src/frontend
diff options
context:
space:
mode:
authorGaming4JC <g4jc@hyperbola.info>2019-12-14 09:16:32 -0500
committerGaming4JC <g4jc@hyperbola.info>2019-12-17 06:25:28 -0500
commitef44324d916b89b95fa0ea77a3d91eafb4359bf8 (patch)
tree38ce7009388ceef8cb6793f5d0dcd5388d1d3a3f /js/src/frontend
parentbbd1fef7840d97801307f9ace021b52d94c5f61f (diff)
downloadUXP-ef44324d916b89b95fa0ea77a3d91eafb4359bf8.tar
UXP-ef44324d916b89b95fa0ea77a3d91eafb4359bf8.tar.gz
UXP-ef44324d916b89b95fa0ea77a3d91eafb4359bf8.tar.lz
UXP-ef44324d916b89b95fa0ea77a3d91eafb4359bf8.tar.xz
UXP-ef44324d916b89b95fa0ea77a3d91eafb4359bf8.zip
Bug 1331092 - Part 7: Implement Async Generator yield*.
Tag #1287
Diffstat (limited to 'js/src/frontend')
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp130
-rw-r--r--js/src/frontend/BytecodeEmitter.h8
2 files changed, 125 insertions, 13 deletions
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 9d6a68609..d926e130c 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2118,7 +2118,7 @@ class ForOfLoopControl : public LoopControl
bool emitIteratorClose(BytecodeEmitter* bce,
CompletionKind completionKind = CompletionKind::Normal) {
ptrdiff_t start = bce->offset();
- if (!bce->emitIteratorClose(completionKind, allowSelfHosted_))
+ if (!bce->emitIteratorClose(IteratorKind::Sync, completionKind, allowSelfHosted_))
return false;
ptrdiff_t end = bce->offset();
return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
@@ -3722,6 +3722,18 @@ BytecodeEmitter::emitFinishIteratorResult(bool done)
}
bool
+BytecodeEmitter::emitToIteratorResult(bool done)
+{
+ if (!emitPrepareIteratorResult()) // VALUE OBJ
+ return false;
+ if (!emit1(JSOP_SWAP)) // OBJ VALUE
+ return false;
+ if (!emitFinishIteratorResult(done)) // RESULT
+ return false;
+ return true;
+}
+
+bool
BytecodeEmitter::emitGetNameAtLocation(JSAtom* name, const NameLocation& loc, bool callContext)
{
switch (loc.kind()) {
@@ -5255,7 +5267,8 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted /* = false
}
bool
-BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = CompletionKind::Normal */,
+BytecodeEmitter::emitIteratorClose(IteratorKind iterKind /* = IteratorKind::Sync */,
+ CompletionKind completionKind /* = CompletionKind::Normal */,
bool allowSelfHosted /* = false */)
{
MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
@@ -5340,6 +5353,11 @@ BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = Completion
return false;
checkTypeSet(JSOP_CALL);
+ if (iterKind == IteratorKind::Async) {
+ if (!emitAwait()) // ... ... RESULT
+ return false;
+ }
+
if (completionKind == CompletionKind::Throw) {
if (!emit1(JSOP_SWAP)) // ... RET ITER RESULT UNDEF
return false;
@@ -5349,7 +5367,7 @@ BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = Completion
if (!tryCatch->emitCatch()) // ... RET ITER RESULT
return false;
- // Just ignore the exception thrown by call.
+ // Just ignore the exception thrown by call and await.
if (!emit1(JSOP_EXCEPTION)) // ... RET ITER RESULT EXC
return false;
if (!emit1(JSOP_POP)) // ... RET ITER RESULT
@@ -6972,6 +6990,63 @@ BytecodeEmitter::emitIterator()
}
bool
+BytecodeEmitter::emitAsyncIterator()
+{
+ // Convert iterable to iterator.
+ if (!emit1(JSOP_DUP)) // OBJ OBJ
+ return false;
+ if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::asyncIterator))) // OBJ OBJ @@ASYNCITERATOR
+ return false;
+ if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
+ return false;
+
+ IfThenElseEmitter ifAsyncIterIsUndefined(this);
+ if (!emit1(JSOP_DUP)) // OBJ ITERFN ITERFN
+ return false;
+ if (!emit1(JSOP_UNDEFINED)) // OBJ ITERFN ITERFN UNDEF
+ return false;
+ if (!emit1(JSOP_EQ)) // OBJ ITERFN EQ
+ return false;
+ if (!ifAsyncIterIsUndefined.emitIfElse()) // OBJ ITERFN
+ return false;
+
+ if (!emit1(JSOP_POP)) // OBJ
+ return false;
+ if (!emit1(JSOP_DUP)) // OBJ OBJ
+ return false;
+ if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) // OBJ OBJ @@ITERATOR
+ return false;
+ if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
+ return false;
+ if (!emit1(JSOP_SWAP)) // ITERFN OBJ
+ return false;
+ if (!emitCall(JSOP_CALLITER, 0)) // ITER
+ return false;
+ checkTypeSet(JSOP_CALLITER);
+ if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
+ return false;
+
+ if (!emit1(JSOP_TOASYNCITER)) // ITER
+ return false;
+
+ if (!ifAsyncIterIsUndefined.emitElse()) // OBJ ITERFN
+ return false;
+
+ if (!emit1(JSOP_SWAP)) // ITERFN OBJ
+ return false;
+ if (!emitCall(JSOP_CALLITER, 0)) // ITER
+ return false;
+ checkTypeSet(JSOP_CALLITER);
+ if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
+ return false;
+
+ if (!ifAsyncIterIsUndefined.emitEnd()) // ITER
+ return false;
+
+ return true;
+}
+
+bool
BytecodeEmitter::emitSpread(bool allowSelfHosted)
{
LoopControl loopInfo(this, StatementKind::Spread);
@@ -8593,6 +8668,16 @@ BytecodeEmitter::emitYield(ParseNode* pn)
}
bool
+BytecodeEmitter::emitAwait()
+{
+ if (!emitGetDotGenerator())
+ return false;
+ if (!emitYieldOp(JSOP_AWAIT))
+ return false;
+ return true;
+}
+
+bool
BytecodeEmitter::emitAwait(ParseNode* pn)
{
MOZ_ASSERT(sc->isFunctionBox());
@@ -8600,11 +8685,7 @@ BytecodeEmitter::emitAwait(ParseNode* pn)
if (!emitTree(pn->pn_kid))
return false;
- if (!emitGetDotGenerator())
- return false;
- if (!emitYieldOp(JSOP_AWAIT))
- return false;
- return true;
+ return emitAwait();
}
bool
@@ -8613,10 +8694,17 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(sc->asFunctionBox()->isStarGenerator());
+ bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
+
if (!emitTree(iter)) // ITERABLE
return false;
- if (!emitIterator()) // ITER
- return false;
+ if (isAsyncGenerator) {
+ if (!emitAsyncIterator()) // ITER
+ return false;
+ } else {
+ if (!emitIterator()) // ITER
+ return false;
+ }
// Initial send value is undefined.
if (!emit1(JSOP_UNDEFINED)) // ITER RECEIVED
@@ -8674,7 +8762,8 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
//
// If the iterator does not have a "throw" method, it calls IteratorClose
// and then throws a TypeError.
- if (!emitIteratorClose()) // ITER RESULT EXCEPTION
+ IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
+ if (!emitIteratorClose(iterKind))
return false;
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
return false;
@@ -8690,6 +8779,12 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
if (!emitCall(JSOP_CALL, 1, iter)) // ITER OLDRESULT RESULT
return false;
checkTypeSet(JSOP_CALL);
+
+ if (isAsyncGenerator) {
+ if (!emitAwait()) // ITER OLDRESULT RESULT
+ return false;
+ }
+
if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) // ITER OLDRESULT RESULT
return false;
if (!emit1(JSOP_SWAP)) // ITER RESULT OLDRESULT
@@ -8756,6 +8851,11 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
return false;
checkTypeSet(JSOP_CALL);
+ if (iterKind == IteratorKind::Async) {
+ if (!emitAwait()) // ... FTYPE FVALUE RESULT
+ return false;
+ }
+
// Step v.
if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ITER OLDRESULT FTYPE FVALUE RESULT
return false;
@@ -8830,9 +8930,15 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
return false;
if (!emitCall(JSOP_CALL, 1, iter)) // ITER RESULT
return false;
+ checkTypeSet(JSOP_CALL);
+
+ if (isAsyncGenerator) {
+ if (!emitAwait()) // ITER RESULT RESULT
+ return false;
+ }
+
if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ITER RESULT
return false;
- checkTypeSet(JSOP_CALL);
MOZ_ASSERT(this->stackDepth == startDepth);
if (!emitJumpTargetAndPatch(checkResult)) // checkResult:
diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
index 67e329489..5eaf5ce14 100644
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -10,6 +10,7 @@
#define frontend_BytecodeEmitter_h
#include "jscntxt.h"
+#include "jsiter.h"
#include "jsopcode.h"
#include "jsscript.h"
@@ -606,6 +607,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitPrepareIteratorResult();
MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
+ MOZ_MUST_USE bool emitToIteratorResult(bool done);
MOZ_MUST_USE bool emitGetDotGenerator();
@@ -613,6 +615,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitYield(ParseNode* pn);
MOZ_MUST_USE bool emitYieldOp(JSOp op);
MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
+ MOZ_MUST_USE bool emitAwait();
MOZ_MUST_USE bool emitAwait(ParseNode* pn);
MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
@@ -708,10 +711,13 @@ struct MOZ_STACK_CLASS BytecodeEmitter
// It will replace that stack value with the corresponding iterator
MOZ_MUST_USE bool emitIterator();
+ MOZ_MUST_USE bool emitAsyncIterator();
+
// 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 emitIteratorClose(CompletionKind completionKind = CompletionKind::Normal,
+ MOZ_MUST_USE bool emitIteratorClose(IteratorKind iterKind = IteratorKind::Sync,
+ CompletionKind completionKind = CompletionKind::Normal,
bool allowSelfHosted = false);
template <typename InnerEmitter>