diff options
Diffstat (limited to 'js/src/builtin/Promise.cpp')
-rw-r--r-- | js/src/builtin/Promise.cpp | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 59e710935..d2b7b543b 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -2329,6 +2329,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, |