Bug 1331092 - Part 7: Implement Async Generator yield*. r=shu

This commit is contained in:
Tooru Fujisawa 2017-03-27 23:20:19 +09:00
Родитель 01c442496d
Коммит 23f20b4a20
14 изменённых файлов: 452 добавлений и 45 удалений

Просмотреть файл

@ -852,7 +852,7 @@ struct JSClass {
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
#define JSCLASS_GLOBAL_SLOT_COUNT \
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 45)
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 46)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \

Просмотреть файл

@ -2299,6 +2299,165 @@ js::AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj
return PerformPromiseThenWithReaction(cx, promise, reaction);
}
// Async Iteration proposal 6.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next
// Async Iteration proposal 6.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return
// Async Iteration proposal 6.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw
bool
js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind)
{
// Step 1.
RootedValue thisVal(cx, args.thisv());
// Step 2.
RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!resultPromise)
return false;
// Step 3.
if (!thisVal.isObject() || !thisVal.toObject().is<AsyncFromSyncIteratorObject>()) {
// Step 3.a.
RootedValue badGeneratorError(cx);
if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_ITERATOR, &badGeneratorError))
return false;
// Step 3.b.
if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
return false;
// Step 3.c.
args.rval().setObject(*resultPromise);
return true;
}
Rooted<AsyncFromSyncIteratorObject*> asyncIter(
cx, &thisVal.toObject().as<AsyncFromSyncIteratorObject>());
// Step 4.
RootedObject iter(cx, asyncIter->iterator());
RootedValue resultVal(cx);
RootedValue func(cx);
if (completionKind == CompletionKind::Normal) {
// 6.1.3.2.1 steps 5-6 (partially).
if (!GetProperty(cx, iter, iter, cx->names().next, &func))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
} else if (completionKind == CompletionKind::Return) {
// 6.1.3.2.2 steps 5-6.
if (!GetProperty(cx, iter, iter, cx->names().return_, &func))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Step 7.
if (func.isNullOrUndefined()) {
// Step 7.a.
RootedObject resultObj(cx, CreateIterResultObject(cx, args.get(0), true));
if (!resultObj)
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
RootedValue resultVal(cx, ObjectValue(*resultObj));
// Step 7.b.
if (!ResolvePromiseInternal(cx, resultPromise, resultVal))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Step 7.c.
args.rval().setObject(*resultPromise);
return true;
}
} else {
// 6.1.3.2.3 steps 5-6.
MOZ_ASSERT(completionKind == CompletionKind::Throw);
if (!GetProperty(cx, iter, iter, cx->names().throw_, &func))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Step 7.
if (func.isNullOrUndefined()) {
// Step 7.a.
if (!RejectMaybeWrappedPromise(cx, resultPromise, args.get(0)))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Step 7.b.
args.rval().setObject(*resultPromise);
return true;
}
}
// 6.1.3.2.1 steps 5-6 (partially).
// 6.1.3.2.2, 6.1.3.2.3 steps 8-9.
RootedValue iterVal(cx, ObjectValue(*iter));
FixedInvokeArgs<1> args2(cx);
args2[0].set(args.get(0));
if (!js::Call(cx, func, iterVal, args2, &resultVal))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// 6.1.3.2.1 steps 5-6 (partially).
// 6.1.3.2.2, 6.1.3.2.3 steps 10.
if (!resultVal.isObject()) {
CheckIsObjectKind kind;
switch (completionKind) {
case CompletionKind::Normal:
kind = CheckIsObjectKind::IteratorNext;
break;
case CompletionKind::Throw:
kind = CheckIsObjectKind::IteratorThrow;
break;
case CompletionKind::Return:
kind = CheckIsObjectKind::IteratorReturn;
break;
}
MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, kind));
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
}
RootedObject resultObj(cx, &resultVal.toObject());
// Following step numbers are for 6.1.3.2.1.
// For 6.1.3.2.2 and 6.1.3.2.3, steps 7-16 corresponds to steps 11-20.
// Steps 7-8.
RootedValue value(cx);
if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Steps 9-10.
RootedValue doneVal(cx);
if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
bool done = ToBoolean(doneVal);
// Step 11.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!promise)
return false;
// Step 12.
if (!ResolvePromiseInternal(cx, promise, value))
return false;
// Steps 13-14.
RootedValue onFulfilled(cx, Int32Value(done
? PromiseHandlerAsyncIteratorValueUnwrapDone
: PromiseHandlerAsyncIteratorValueUnwrapNotDone));
RootedObject incumbentGlobal(cx);
if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
return false;
// Step 15.
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled,
UndefinedHandleValue,
nullptr, nullptr,
incumbentGlobal));
if (!reaction)
return false;
if (!PerformPromiseThenWithReaction(cx, promise, reaction))
return false;
// Step 16.
args.rval().setObject(*resultPromise);
return true;
}
// Async Iteration proposal 6.4.3.3.
MOZ_MUST_USE bool
js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,

Просмотреть файл

@ -152,6 +152,9 @@ MOZ_MUST_USE bool
AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal, CompletionKind completionKind,
HandleValue completionValue, MutableHandleValue result);
bool
AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind);
/**
* A PromiseTask represents a task that can be dispatched to a helper thread
* (via StartPromiseTask), executed (by implementing PromiseTask::execute()),

Просмотреть файл

@ -2064,7 +2064,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);
@ -3676,6 +3676,18 @@ BytecodeEmitter::emitFinishIteratorResult(bool done)
return true;
}
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)
{
@ -5231,7 +5243,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,
@ -5316,6 +5329,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;
@ -5325,7 +5343,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
@ -6746,6 +6764,63 @@ BytecodeEmitter::emitIterator()
return true;
}
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)
{
@ -8367,13 +8442,8 @@ BytecodeEmitter::emitYield(ParseNode* pn)
}
bool
BytecodeEmitter::emitAwait(ParseNode* pn)
BytecodeEmitter::emitAwait()
{
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
if (!emitTree(pn->pn_kid))
return false;
if (!emitGetDotGenerator())
return false;
if (!emitYieldOp(JSOP_AWAIT))
@ -8381,16 +8451,34 @@ BytecodeEmitter::emitAwait(ParseNode* pn)
return true;
}
bool
BytecodeEmitter::emitAwait(ParseNode* pn)
{
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
if (!emitTree(pn->pn_kid))
return false;
return emitAwait();
}
bool
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
@ -8448,7 +8536,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)) // ITER RESULT EXCEPTION
return false;
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
return false;
@ -8464,6 +8553,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
@ -8530,6 +8625,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;
@ -8602,9 +8702,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:

Просмотреть файл

@ -10,6 +10,7 @@
#define frontend_BytecodeEmitter_h
#include "jscntxt.h"
#include "jsiter.h"
#include "jsopcode.h"
#include "jsscript.h"
@ -605,6 +606,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();
@ -612,6 +614,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);
@ -694,10 +697,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>

Просмотреть файл

@ -594,3 +594,5 @@ MSG_DEF(JSMSG_ITERATOR_NO_THROW, 0, JSEXN_TYPEERR, "iterator does not have
// Async Iteration
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")

Просмотреть файл

@ -221,6 +221,8 @@ InitLegacyIteratorClass(JSContext* cx, HandleObject obj);
extern JSObject*
InitStopIterationClass(JSContext* cx, HandleObject obj);
enum class IteratorKind { Sync, Async };
} /* namespace js */
#endif /* jsiter_h */

Просмотреть файл

@ -148,6 +148,69 @@ js::AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> a
return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
}
const Class AsyncFromSyncIteratorObject::class_ = {
"AsyncFromSyncIteratorObject",
JSCLASS_HAS_RESERVED_SLOTS(AsyncFromSyncIteratorObject::Slots)
};
// Async Iteration proposal 6.1.3.1.
JSObject*
js::CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter)
{
// Step 1 (implicit).
// Done in bytecode emitted by emitAsyncIterator.
// Steps 2-4.
return AsyncFromSyncIteratorObject::create(cx, iter);
}
// Async Iteration proposal 6.1.3.1 steps 2-4.
/* static */ JSObject*
AsyncFromSyncIteratorObject::create(JSContext* cx, HandleObject iter)
{
// Step 2.
RootedObject proto(cx, GlobalObject::getOrCreateAsyncFromSyncIteratorPrototype(cx,
cx->global()));
if (!proto)
return nullptr;
RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, proto));
if (!obj)
return nullptr;
Handle<AsyncFromSyncIteratorObject*> asyncIter = obj.as<AsyncFromSyncIteratorObject>();
// Step 3.
asyncIter->setIterator(iter);
// Step 4.
return asyncIter;
}
// Async Iteration proposal 6.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next.
static bool
AsyncFromSyncIteratorNext(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Normal);
}
// Async Iteration proposal 6.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return.
static bool
AsyncFromSyncIteratorReturn(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Return);
}
// Async Iteration proposal 6.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw.
static bool
AsyncFromSyncIteratorThrow(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Throw);
}
// Async Iteration proposal 6.4.1.2 AsyncGenerator.prototype.next.
static bool
AsyncGeneratorNext(JSContext* cx, unsigned argc, Value* vp)
@ -413,17 +476,17 @@ js::AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncG
return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
}
// Async Iteration proposal 6.2.1.2 (partially).
// Async Iteration proposal 6.2.1.3 (partially).
// Most steps are done in generator.
static MOZ_MUST_USE bool
AsyncGeneratorYield(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value, bool done)
HandleValue value)
{
// Step 6.
// Step 5.
asyncGenObj->setSuspendedYield();
// Step 10.c.
return AsyncGeneratorResolve(cx, asyncGenObj, value, done);
// Step 8.
return AsyncGeneratorResolve(cx, asyncGenObj, value, false);
}
// Async Iteration proposal 6.4.3.5 steps 12-14, 16-20.
@ -451,41 +514,29 @@ AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
return AsyncGeneratorThrown(cx, asyncGenObj);
}
if (asyncGenObj->generatorObj()->isAfterAwait())
return AsyncGeneratorAwait(cx, asyncGenObj, result);
// The following code corresponds to the following 3 cases:
// * yield
// * await
// * yield*
// * return
// For await and return, property access is done on an internal result
// For yield and return, property access is done on an internal result
// object and it's not observable.
// For yield, it's done on an user-provided result object, and it's
// observable, so perform in that order in all cases.
// For yield*, it's done on a possibly user-provided result object, and
// it's observable.
// 2.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
RootedObject resultObj(cx, &result.toObject());
RootedValue value(cx);
RootedValue doneVal(cx);
// 6.2.1.2 step 10.a.
if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
return false;
// 6.2.1.2 step 10.b.
if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
return false;
// 6.2.1.2 step 10.c.
if (asyncGenObj->generatorObj()->isAfterYield())
return AsyncGeneratorYield(cx, asyncGenObj, value, ToBoolean(doneVal));
return AsyncGeneratorYield(cx, asyncGenObj, value);
// 6.4.3.2 step 5.d-g.
if (ToBoolean(doneVal)) {
MOZ_ASSERT(!asyncGenObj->generatorObj()->isAfterAwait());
return AsyncGeneratorReturned(cx, asyncGenObj, value);
}
MOZ_ASSERT(asyncGenObj->generatorObj()->isAfterAwait());
// 5.1 steps 2-9.
return AsyncGeneratorAwait(cx, asyncGenObj, value);
return AsyncGeneratorReturned(cx, asyncGenObj, value);
}
static const JSFunctionSpec async_iterator_proto_methods[] = {
@ -493,6 +544,13 @@ static const JSFunctionSpec async_iterator_proto_methods[] = {
JS_FS_END
};
static const JSFunctionSpec async_from_sync_iter_methods[] = {
JS_FN("next", AsyncFromSyncIteratorNext, 1, 0),
JS_FN("throw", AsyncFromSyncIteratorThrow, 1, 0),
JS_FN("return", AsyncFromSyncIteratorReturn, 1, 0),
JS_FS_END
};
static const JSFunctionSpec async_generator_methods[] = {
JS_FN("next", AsyncGeneratorNext, 1, 0),
JS_FN("throw", AsyncGeneratorThrow, 1, 0),
@ -513,6 +571,19 @@ GlobalObject::initAsyncGenerators(JSContext* cx, Handle<GlobalObject*> global)
if (!DefinePropertiesAndFunctions(cx, asyncIterProto, nullptr, async_iterator_proto_methods))
return false;
// Async Iteration proposal 6.1.3.2 %AsyncFromSyncIteratorPrototype%.
RootedObject asyncFromSyncIterProto(
cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
asyncIterProto));
if (!asyncFromSyncIterProto)
return false;
if (!DefinePropertiesAndFunctions(cx, asyncFromSyncIterProto, nullptr,
async_from_sync_iter_methods) ||
!DefineToStringTag(cx, asyncFromSyncIterProto, cx->names().AsyncFromSyncIterator))
{
return false;
}
// Async Iteration proposal 6.4.1 %AsyncGeneratorPrototype%.
RootedObject asyncGenProto(
cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
@ -557,6 +628,7 @@ GlobalObject::initAsyncGenerators(JSContext* cx, Handle<GlobalObject*> global)
}
global->setReservedSlot(ASYNC_ITERATOR_PROTO, ObjectValue(*asyncIterProto));
global->setReservedSlot(ASYNC_FROM_SYNC_ITERATOR_PROTO, ObjectValue(*asyncFromSyncIterProto));
global->setReservedSlot(ASYNC_GENERATOR, ObjectValue(*asyncGenerator));
global->setReservedSlot(ASYNC_GENERATOR_FUNCTION, ObjectValue(*asyncGenFunction));
global->setReservedSlot(ASYNC_GENERATOR_PROTO, ObjectValue(*asyncGenProto));

Просмотреть файл

@ -196,6 +196,32 @@ class AsyncGeneratorObject : public NativeObject
}
};
JSObject*
CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter);
class AsyncFromSyncIteratorObject : public NativeObject
{
private:
enum AsyncFromSyncIteratorObjectSlots {
Slot_Iterator = 0,
Slots
};
void setIterator(HandleObject iterator_) {
setFixedSlot(Slot_Iterator, ObjectValue(*iterator_));
}
public:
static const Class class_;
static JSObject*
create(JSContext* cx, HandleObject iter);
JSObject* iterator() const {
return &getFixedSlot(Slot_Iterator).toObject();
}
};
MOZ_MUST_USE bool
AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);

Просмотреть файл

@ -30,6 +30,7 @@
macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
macro(as, as, "as") \
macro(Async, Async, "Async") \
macro(AsyncFromSyncIterator, AsyncFromSyncIterator, "Async-from-Sync Iterator") \
macro(AsyncFunction, AsyncFunction, "AsyncFunction") \
macro(AsyncGenerator, AsyncGenerator, "AsyncGenerator") \
macro(AsyncGeneratorFunction, AsyncGeneratorFunction, "AsyncGeneratorFunction") \

Просмотреть файл

@ -99,6 +99,7 @@ class GlobalObject : public NativeObject
ASYNC_FUNCTION_PROTO,
ASYNC_FUNCTION,
ASYNC_ITERATOR_PROTO,
ASYNC_FROM_SYNC_ITERATOR_PROTO,
ASYNC_GENERATOR,
ASYNC_GENERATOR_FUNCTION,
ASYNC_GENERATOR_PROTO,
@ -640,6 +641,12 @@ class GlobalObject : public NativeObject
initAsyncGenerators));
}
static NativeObject*
getOrCreateAsyncFromSyncIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_FROM_SYNC_ITERATOR_PROTO,
initAsyncGenerators));
}
static NativeObject*
getOrCreateAsyncGenerator(JSContext* cx, Handle<GlobalObject*> global) {
return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_GENERATOR,

Просмотреть файл

@ -1923,7 +1923,6 @@ CASE(EnableInterruptsPseudoOpcode)
/* Various 1-byte no-ops. */
CASE(JSOP_NOP)
CASE(JSOP_NOP_DESTRUCTURING)
CASE(JSOP_UNUSED210)
CASE(JSOP_UNUSED211)
CASE(JSOP_UNUSED220)
CASE(JSOP_UNUSED221)
@ -3578,6 +3577,17 @@ CASE(JSOP_TOASYNCGEN)
}
END_CASE(JSOP_TOASYNCGEN)
CASE(JSOP_TOASYNCITER)
{
ReservedRooted<JSObject*> iter(&rootObject1, &REGS.sp[-1].toObject());
JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter);
if (!asyncIter)
goto error;
REGS.sp[-1].setObject(*asyncIter);
}
END_CASE(JSOP_TOASYNCITER)
CASE(JSOP_SETFUNNAME)
{
MOZ_ASSERT(REGS.stackDepth() >= 2);
@ -5099,6 +5109,10 @@ js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind)
case CheckIsObjectKind::GetIterator:
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_GET_ITER_RETURNED_PRIMITIVE);
break;
case CheckIsObjectKind::GetAsyncIterator:
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
break;
default:
MOZ_CRASH("Unknown kind");
}

Просмотреть файл

@ -556,7 +556,8 @@ enum class CheckIsObjectKind : uint8_t {
IteratorNext,
IteratorReturn,
IteratorThrow,
GetIterator
GetIterator,
GetAsyncIterator
};
bool

Просмотреть файл

@ -2152,7 +2152,15 @@
* Stack: promise, gen => resolved
*/ \
macro(JSOP_AWAIT, 209, "await", NULL, 4, 2, 1, JOF_UINT24) \
macro(JSOP_UNUSED210, 210, "unused210", NULL, 1, 0, 0, JOF_BYTE) \
/*
* Pops the iterator from the top of the stack, and create async iterator
* from it and push the async iterator back onto the stack.
* Category: Statements
* Type: Generator
* Operands:
* Stack: iter => asynciter
*/ \
macro(JSOP_TOASYNCITER, 210, "toasynciter", NULL, 1, 1, 1, JOF_BYTE) \
macro(JSOP_UNUSED211, 211, "unused211", NULL, 1, 0, 0, JOF_BYTE) \
/*
* Initializes generator frame, creates a generator and pushes it on the