LCOV - code coverage report
Current view: top level - js/src/vm - AsyncIteration.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 2 262 0.8 %
Date: 2017-07-14 16:53:18 Functions: 1 28 3.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "vm/AsyncIteration.h"
       8             : 
       9             : #include "jsarray.h"
      10             : #include "jscompartment.h"
      11             : 
      12             : #include "builtin/Promise.h"
      13             : #include "vm/GeneratorObject.h"
      14             : #include "vm/GlobalObject.h"
      15             : #include "vm/Interpreter.h"
      16             : #include "vm/SelfHosting.h"
      17             : 
      18             : #include "jscntxtinlines.h"
      19             : #include "jsobjinlines.h"
      20             : 
      21             : #include "vm/NativeObject-inl.h"
      22             : 
      23             : using namespace js;
      24             : using namespace js::gc;
      25             : 
      26             : #define UNWRAPPED_ASYNC_WRAPPED_SLOT 1
      27             : #define WRAPPED_ASYNC_UNWRAPPED_SLOT 0
      28             : 
      29             : // Async Iteration proposal 2.3.10 Runtime Semantics: EvaluateBody.
      30             : static bool
      31           0 : WrappedAsyncGenerator(JSContext* cx, unsigned argc, Value* vp)
      32             : {
      33           0 :     CallArgs args = CallArgsFromVp(argc, vp);
      34             : 
      35           0 :     RootedFunction wrapped(cx, &args.callee().as<JSFunction>());
      36           0 :     RootedValue unwrappedVal(cx, wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT));
      37           0 :     RootedFunction unwrapped(cx, &unwrappedVal.toObject().as<JSFunction>());
      38           0 :     RootedValue thisValue(cx, args.thisv());
      39             : 
      40             :     // Step 1.
      41           0 :     RootedValue generatorVal(cx);
      42           0 :     InvokeArgs args2(cx);
      43           0 :     if (!args2.init(cx, argc))
      44           0 :         return false;
      45           0 :     for (size_t i = 0, len = argc; i < len; i++)
      46           0 :         args2[i].set(args[i]);
      47           0 :     if (!Call(cx, unwrappedVal, thisValue, args2, &generatorVal))
      48           0 :         return false;
      49             : 
      50             :     // Step 2.
      51             :     Rooted<AsyncGeneratorObject*> asyncGenObj(
      52           0 :         cx, AsyncGeneratorObject::create(cx, wrapped, generatorVal));
      53           0 :     if (!asyncGenObj)
      54           0 :         return false;
      55             : 
      56             :     // Step 3 (skipped).
      57             :     // Done in AsyncGeneratorObject::create and generator.
      58             : 
      59             :     // Step 4.
      60           0 :     args.rval().setObject(*asyncGenObj);
      61           0 :     return true;
      62             : }
      63             : 
      64             : JSObject*
      65           0 : js::WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
      66             : {
      67           0 :     MOZ_ASSERT(unwrapped->isAsync());
      68           0 :     MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
      69             :                       "%FunctionPrototype% fallback in NewFunctionWithProto().");
      70             : 
      71             :     // Create a new function with AsyncGeneratorPrototype, reusing the name and
      72             :     // the length of `unwrapped`.
      73             : 
      74           0 :     RootedAtom funName(cx, unwrapped->explicitName());
      75             :     uint16_t length;
      76           0 :     if (!JSFunction::getLength(cx, unwrapped, &length))
      77           0 :         return nullptr;
      78             : 
      79           0 :     RootedFunction wrapped(cx, NewFunctionWithProto(cx, WrappedAsyncGenerator, length,
      80             :                                                     JSFunction::NATIVE_FUN, nullptr,
      81             :                                                     funName, proto,
      82             :                                                     AllocKind::FUNCTION_EXTENDED,
      83           0 :                                                     TenuredObject));
      84           0 :     if (!wrapped)
      85           0 :         return nullptr;
      86             : 
      87           0 :     if (unwrapped->hasCompileTimeName())
      88           0 :         wrapped->setCompileTimeName(unwrapped->compileTimeName());
      89             : 
      90             :     // Link them to each other to make GetWrappedAsyncGenerator and
      91             :     // GetUnwrappedAsyncGenerator work.
      92           0 :     unwrapped->setExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
      93           0 :     wrapped->setExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
      94             : 
      95           0 :     return wrapped;
      96             : }
      97             : 
      98             : JSObject*
      99           0 : js::WrapAsyncGenerator(JSContext* cx, HandleFunction unwrapped)
     100             : {
     101           0 :     RootedObject proto(cx, GlobalObject::getOrCreateAsyncGenerator(cx, cx->global()));
     102           0 :     if (!proto)
     103           0 :         return nullptr;
     104             : 
     105           0 :     return WrapAsyncGeneratorWithProto(cx, unwrapped, proto);
     106             : }
     107             : 
     108             : bool
     109        3521 : js::IsWrappedAsyncGenerator(JSFunction* fun)
     110             : {
     111        3521 :     return fun->maybeNative() == WrappedAsyncGenerator;
     112             : }
     113             : 
     114             : JSFunction*
     115           0 : js::GetWrappedAsyncGenerator(JSFunction* unwrapped)
     116             : {
     117           0 :     MOZ_ASSERT(unwrapped->isAsync());
     118           0 :     return &unwrapped->getExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
     119             : }
     120             : 
     121             : JSFunction*
     122           0 : js::GetUnwrappedAsyncGenerator(JSFunction* wrapped)
     123             : {
     124           0 :     MOZ_ASSERT(IsWrappedAsyncGenerator(wrapped));
     125           0 :     JSFunction* unwrapped = &wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT)
     126           0 :                             .toObject().as<JSFunction>();
     127           0 :     MOZ_ASSERT(unwrapped->isAsync());
     128           0 :     return unwrapped;
     129             : }
     130             : 
     131             : static MOZ_MUST_USE bool
     132             : AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     133             :                      CompletionKind completionKind, HandleValue argument);
     134             : 
     135             : // Async Iteration proposal 5.1.1 Await Fulfilled Functions.
     136             : MOZ_MUST_USE bool
     137           0 : js::AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     138             :                                    HandleValue value)
     139             : {
     140           0 :     return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Normal, value);
     141             : }
     142             : 
     143             : // Async Iteration proposal 5.1.2 Await Rejected Functions.
     144             : MOZ_MUST_USE bool
     145           0 : js::AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     146             :                                   HandleValue reason)
     147             : {
     148           0 :     return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
     149             : }
     150             : 
     151             : const Class AsyncFromSyncIteratorObject::class_ = {
     152             :     "AsyncFromSyncIteratorObject",
     153             :     JSCLASS_HAS_RESERVED_SLOTS(AsyncFromSyncIteratorObject::Slots)
     154             : };
     155             : 
     156             : // Async Iteration proposal 6.1.3.1.
     157             : JSObject*
     158           0 : js::CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter)
     159             : {
     160             :     // Step 1 (implicit).
     161             :     // Done in bytecode emitted by emitAsyncIterator.
     162             : 
     163             :     // Steps 2-4.
     164           0 :     return AsyncFromSyncIteratorObject::create(cx, iter);
     165             : }
     166             : 
     167             : // Async Iteration proposal 6.1.3.1 steps 2-4.
     168             : /* static */ JSObject*
     169           0 : AsyncFromSyncIteratorObject::create(JSContext* cx, HandleObject iter)
     170             : {
     171             :     // Step 2.
     172           0 :     RootedObject proto(cx, GlobalObject::getOrCreateAsyncFromSyncIteratorPrototype(cx,
     173           0 :                                                                                    cx->global()));
     174           0 :     if (!proto)
     175           0 :         return nullptr;
     176             : 
     177           0 :     RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, proto));
     178           0 :     if (!obj)
     179           0 :         return nullptr;
     180             : 
     181           0 :     Handle<AsyncFromSyncIteratorObject*> asyncIter = obj.as<AsyncFromSyncIteratorObject>();
     182             : 
     183             :     // Step 3.
     184           0 :     asyncIter->setIterator(iter);
     185             : 
     186             :     // Step 4.
     187           0 :     return asyncIter;
     188             : }
     189             : 
     190             : // Async Iteration proposal 6.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next.
     191             : static bool
     192           0 : AsyncFromSyncIteratorNext(JSContext* cx, unsigned argc, Value* vp)
     193             : {
     194           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     195           0 :     return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Normal);
     196             : }
     197             : 
     198             : // Async Iteration proposal 6.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return.
     199             : static bool
     200           0 : AsyncFromSyncIteratorReturn(JSContext* cx, unsigned argc, Value* vp)
     201             : {
     202           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     203           0 :     return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Return);
     204             : }
     205             : 
     206             : // Async Iteration proposal 6.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw.
     207             : static bool
     208           0 : AsyncFromSyncIteratorThrow(JSContext* cx, unsigned argc, Value* vp)
     209             : {
     210           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     211           0 :     return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Throw);
     212             : }
     213             : 
     214             : // Async Iteration proposal 6.4.1.2 AsyncGenerator.prototype.next.
     215             : static bool
     216           0 : AsyncGeneratorNext(JSContext* cx, unsigned argc, Value* vp)
     217             : {
     218           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     219             : 
     220             :     // Steps 1-3.
     221           0 :     return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Normal, args.get(0),
     222           0 :                                  args.rval());
     223             : }
     224             : 
     225             : // Async Iteration proposal 6.4.1.3 AsyncGenerator.prototype.return.
     226             : static bool
     227           0 : AsyncGeneratorReturn(JSContext* cx, unsigned argc, Value* vp)
     228             : {
     229           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     230             : 
     231             :     // Steps 1-3.
     232           0 :     return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Return, args.get(0),
     233           0 :                                  args.rval());
     234             : }
     235             : 
     236             : // Async Iteration proposal 6.4.1.4 AsyncGenerator.prototype.throw.
     237             : static bool
     238           0 : AsyncGeneratorThrow(JSContext* cx, unsigned argc, Value* vp)
     239             : {
     240           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     241             : 
     242             :     // Steps 1-3.
     243           0 :     return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Throw, args.get(0),
     244           0 :                                  args.rval());
     245             : }
     246             : 
     247             : const Class AsyncGeneratorObject::class_ = {
     248             :     "AsyncGenerator",
     249             :     JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorObject::Slots)
     250             : };
     251             : 
     252             : // ES 2017 draft 9.1.13.
     253             : template <typename ProtoGetter>
     254             : static JSObject*
     255           0 : OrdinaryCreateFromConstructor(JSContext* cx, HandleFunction fun,
     256             :                               ProtoGetter protoGetter, const Class* clasp)
     257             : {
     258             :     // Step 1 (skipped).
     259             : 
     260             :     // Step 2.
     261           0 :     RootedValue protoVal(cx);
     262           0 :     if (!GetProperty(cx, fun, fun, cx->names().prototype, &protoVal))
     263           0 :         return nullptr;
     264             : 
     265           0 :     RootedObject proto(cx, protoVal.isObject() ? &protoVal.toObject() : nullptr);
     266           0 :     if (!proto) {
     267           0 :         proto = protoGetter(cx, cx->global());
     268           0 :         if (!proto)
     269           0 :             return nullptr;
     270             :     }
     271             : 
     272             :     // Step 3.
     273           0 :     return NewNativeObjectWithGivenProto(cx, clasp, proto);
     274             : }
     275             : 
     276             : /* static */ AsyncGeneratorObject*
     277           0 : AsyncGeneratorObject::create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal)
     278             : {
     279           0 :     MOZ_ASSERT(generatorVal.isObject());
     280           0 :     MOZ_ASSERT(generatorVal.toObject().is<GeneratorObject>());
     281             : 
     282             :     RootedObject obj(
     283           0 :         cx, OrdinaryCreateFromConstructor(cx, asyncGen,
     284             :                                           GlobalObject::getOrCreateAsyncGeneratorPrototype,
     285           0 :                                           &class_));
     286           0 :     if (!obj)
     287           0 :         return nullptr;
     288             : 
     289           0 :     Handle<AsyncGeneratorObject*> asyncGenObj = obj.as<AsyncGeneratorObject>();
     290             : 
     291             :     // Async Iteration proposal 6.4.3.2 AsyncGeneratorStart.
     292             :     // Step 6.
     293           0 :     asyncGenObj->setGenerator(generatorVal);
     294             : 
     295             :     // Step 7.
     296           0 :     asyncGenObj->setSuspendedStart();
     297             : 
     298             :     // Step 8.
     299           0 :     asyncGenObj->clearSingleQueueRequest();
     300             : 
     301           0 :     return asyncGenObj;
     302             : }
     303             : 
     304             : /* static */ MOZ_MUST_USE bool
     305           0 : AsyncGeneratorObject::enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     306             :                                      Handle<AsyncGeneratorRequest*> request)
     307             : {
     308           0 :     if (asyncGenObj->isSingleQueue()) {
     309           0 :         if (asyncGenObj->isSingleQueueEmpty()) {
     310           0 :             asyncGenObj->setSingleQueueRequest(request);
     311           0 :             return true;
     312             :         }
     313             : 
     314           0 :         RootedArrayObject queue(cx, NewDenseEmptyArray(cx));
     315           0 :         if (!queue)
     316           0 :             return false;
     317             : 
     318           0 :         if (!NewbornArrayPush(cx, queue, ObjectValue(*asyncGenObj->singleQueueRequest())))
     319           0 :             return false;
     320           0 :         if (!NewbornArrayPush(cx, queue, ObjectValue(*request)))
     321           0 :             return false;
     322             : 
     323           0 :         asyncGenObj->setQueue(queue);
     324           0 :         return true;
     325             :     }
     326             : 
     327           0 :     RootedArrayObject queue(cx, asyncGenObj->queue());
     328             : 
     329           0 :     FixedInvokeArgs<1> args(cx);
     330           0 :     args[0].setObject(*request);
     331           0 :     args.setThis(ObjectValue(*queue));
     332           0 :     return CallJSNative(cx, array_push, args);
     333             : }
     334             : 
     335             : /* static */ AsyncGeneratorRequest*
     336           0 : AsyncGeneratorObject::dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
     337             : {
     338           0 :     if (asyncGenObj->isSingleQueue()) {
     339           0 :         AsyncGeneratorRequest* request = asyncGenObj->singleQueueRequest();
     340           0 :         asyncGenObj->clearSingleQueueRequest();
     341           0 :         return request;
     342             :     }
     343             : 
     344           0 :     RootedArrayObject queue(cx, asyncGenObj->queue());
     345             : 
     346           0 :     FixedInvokeArgs<0> args(cx);
     347           0 :     args.setThis(ObjectValue(*queue));
     348           0 :     if (!CallJSNative(cx, array_shift, args))
     349           0 :         return nullptr;
     350             : 
     351           0 :     return &args.rval().toObject().as<AsyncGeneratorRequest>();
     352             : }
     353             : 
     354             : /* static */ AsyncGeneratorRequest*
     355           0 : AsyncGeneratorObject::peekRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
     356             : {
     357           0 :     if (asyncGenObj->isSingleQueue())
     358           0 :         return asyncGenObj->singleQueueRequest();
     359             : 
     360           0 :     RootedArrayObject queue(cx, asyncGenObj->queue());
     361             : 
     362           0 :     RootedValue requestVal(cx);
     363           0 :     if (!GetElement(cx, queue, queue, 0, &requestVal))
     364           0 :         return nullptr;
     365             : 
     366           0 :     return &requestVal.toObject().as<AsyncGeneratorRequest>();
     367             : }
     368             : 
     369             : const Class AsyncGeneratorRequest::class_ = {
     370             :     "AsyncGeneratorRequest",
     371             :     JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorRequest::Slots)
     372             : };
     373             : 
     374             : // Async Iteration proposal 6.4.3.1.
     375             : /* static */ AsyncGeneratorRequest*
     376           0 : AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind_,
     377             :                               HandleValue completionValue_, HandleObject promise_)
     378             : {
     379           0 :     RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, nullptr));
     380           0 :     if (!obj)
     381           0 :         return nullptr;
     382             : 
     383           0 :     Handle<AsyncGeneratorRequest*> request = obj.as<AsyncGeneratorRequest>();
     384           0 :     request->setCompletionKind(completionKind_);
     385           0 :     request->setCompletionValue(completionValue_);
     386           0 :     request->setPromise(promise_);
     387           0 :     return request;
     388             : }
     389             : 
     390             : // Async Iteration proposal 6.4.3.2 steps 5.d-g.
     391             : static MOZ_MUST_USE bool
     392           0 : AsyncGeneratorReturned(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     393             :                        HandleValue value)
     394             : {
     395             :     // Step 5.d.
     396           0 :     asyncGenObj->setCompleted();
     397             : 
     398             :     // Step 5.e (done in bytecode).
     399             :     // Step 5.f.i (implicit).
     400             : 
     401             :     // Step 5.g.
     402           0 :     return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
     403             : }
     404             : 
     405             : // Async Iteration proposal 6.4.3.2 steps 5.d, f.
     406             : static MOZ_MUST_USE bool
     407           0 : AsyncGeneratorThrown(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
     408             : {
     409             :     // Step 5.d.
     410           0 :     asyncGenObj->setCompleted();
     411             : 
     412             :     // Not much we can do about uncatchable exceptions, so just bail.
     413           0 :     if (!cx->isExceptionPending())
     414           0 :         return false;
     415             : 
     416             :     // Step 5.f.i.
     417           0 :     RootedValue value(cx);
     418           0 :     if (!GetAndClearException(cx, &value))
     419           0 :         return false;
     420             : 
     421             :     // Step 5.f.ii.
     422           0 :     return AsyncGeneratorReject(cx, asyncGenObj, value);
     423             : }
     424             : 
     425             : // Async Iteration proposal 6.4.3.5.
     426             : MOZ_MUST_USE bool
     427           0 : js::AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
     428             : {
     429             :     // Step 1 (implicit).
     430             : 
     431             :     // Steps 2-3.
     432           0 :     MOZ_ASSERT(!asyncGenObj->isExecuting());
     433             : 
     434             :     // Steps 4-5.
     435           0 :     if (asyncGenObj->isQueueEmpty())
     436           0 :         return true;
     437             : 
     438             :     // Steps 6-7.
     439             :     Rooted<AsyncGeneratorRequest*> request(
     440           0 :         cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj));
     441           0 :     if (!request)
     442           0 :         return false;
     443             : 
     444             :     // Step 8.
     445           0 :     CompletionKind completionKind = request->completionKind();
     446             : 
     447             :     // Step 9.
     448           0 :     if (completionKind != CompletionKind::Normal) {
     449             :         // Step 9.a.
     450           0 :         if (asyncGenObj->isSuspendedStart())
     451           0 :             asyncGenObj->setCompleted();
     452             : 
     453             :         // Step 9.b.
     454           0 :         if (asyncGenObj->isCompleted()) {
     455             :             // Step 9.b.i.
     456           0 :             RootedValue value(cx, request->completionValue());
     457           0 :             if (completionKind == CompletionKind::Return)
     458           0 :                 return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
     459             :             // Step 9.b.ii.
     460           0 :             return AsyncGeneratorReject(cx, asyncGenObj, value);
     461             :         }
     462           0 :     } else if (asyncGenObj->isCompleted()) {
     463             :         // Step 10.
     464           0 :         return AsyncGeneratorResolve(cx, asyncGenObj, UndefinedHandleValue, true);
     465             :     }
     466             : 
     467             :     // Step 11.
     468           0 :     MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield());
     469             : 
     470             :     // Step 15 (reordered).
     471           0 :     asyncGenObj->setExecuting();
     472             : 
     473           0 :     RootedValue argument(cx, request->completionValue());
     474             : 
     475             :     // Steps 12-14, 16-20.
     476           0 :     return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
     477             : }
     478             : 
     479             : // Async Iteration proposal 6.2.1.3 (partially).
     480             : // Most steps are done in generator.
     481             : static MOZ_MUST_USE bool
     482           0 : AsyncGeneratorYield(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     483             :                     HandleValue value)
     484             : {
     485             :     // Step 5.
     486           0 :     asyncGenObj->setSuspendedYield();
     487             : 
     488             :     // Step 8.
     489           0 :     return AsyncGeneratorResolve(cx, asyncGenObj, value, false);
     490             : }
     491             : 
     492             : // Async Iteration proposal 6.4.3.5 steps 12-14, 16-20.
     493             : // Async Iteration proposal 6.2.1.2 step 10.
     494             : // Async Iteration proposal 6.4.3.2 step 5.f-g.
     495             : // Async Iteration proposal 5.1 steps 2-9.
     496             : // Execution context switching is handled in generator.
     497             : static MOZ_MUST_USE bool
     498           0 : AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     499             :                      CompletionKind completionKind, HandleValue argument)
     500             : {
     501           0 :     RootedValue generatorVal(cx, asyncGenObj->generatorVal());
     502             : 
     503             :     // 6.4.3.5 steps 12-14, 16-20.
     504             :     HandlePropertyName funName = completionKind == CompletionKind::Normal
     505           0 :                                  ? cx->names().StarGeneratorNext
     506             :                                  : completionKind == CompletionKind::Throw
     507           0 :                                  ? cx->names().StarGeneratorThrow
     508           0 :                                  : cx->names().StarGeneratorReturn;
     509           0 :     FixedInvokeArgs<1> args(cx);
     510           0 :     args[0].set(argument);
     511           0 :     RootedValue result(cx);
     512           0 :     if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result)) {
     513             :         // 6.4.3.2 step 5.d, f.
     514           0 :         return AsyncGeneratorThrown(cx, asyncGenObj);
     515             :     }
     516             : 
     517           0 :     if (asyncGenObj->generatorObj()->isAfterAwait())
     518           0 :         return AsyncGeneratorAwait(cx, asyncGenObj, result);
     519             : 
     520             :     // The following code corresponds to the following 3 cases:
     521             :     //   * yield
     522             :     //   * yield*
     523             :     //   * return
     524             :     // For yield and return, property access is done on an internal result
     525             :     // object and it's not observable.
     526             :     // For yield*, it's done on a possibly user-provided result object, and
     527             :     // it's observable.
     528             : 
     529             :     // 2.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
     530           0 :     RootedObject resultObj(cx, &result.toObject());
     531           0 :     RootedValue value(cx);
     532           0 :     if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
     533           0 :         return false;
     534             : 
     535           0 :     if (asyncGenObj->generatorObj()->isAfterYield())
     536           0 :         return AsyncGeneratorYield(cx, asyncGenObj, value);
     537             : 
     538             :     // 6.4.3.2 step 5.d-g.
     539           0 :     return AsyncGeneratorReturned(cx, asyncGenObj, value);
     540             : }
     541             : 
     542             : static const JSFunctionSpec async_iterator_proto_methods[] = {
     543             :     JS_SELF_HOSTED_SYM_FN(asyncIterator, "AsyncIteratorIdentity", 0, 0),
     544             :     JS_FS_END
     545             : };
     546             : 
     547             : static const JSFunctionSpec async_from_sync_iter_methods[] = {
     548             :     JS_FN("next", AsyncFromSyncIteratorNext, 1, 0),
     549             :     JS_FN("throw", AsyncFromSyncIteratorThrow, 1, 0),
     550             :     JS_FN("return", AsyncFromSyncIteratorReturn, 1, 0),
     551             :     JS_FS_END
     552             : };
     553             : 
     554             : static const JSFunctionSpec async_generator_methods[] = {
     555             :     JS_FN("next", AsyncGeneratorNext, 1, 0),
     556             :     JS_FN("throw", AsyncGeneratorThrow, 1, 0),
     557             :     JS_FN("return", AsyncGeneratorReturn, 1, 0),
     558             :     JS_FS_END
     559             : };
     560             : 
     561             : /* static */ MOZ_MUST_USE bool
     562           0 : GlobalObject::initAsyncGenerators(JSContext* cx, Handle<GlobalObject*> global)
     563             : {
     564           0 :     if (global->getReservedSlot(ASYNC_ITERATOR_PROTO).isObject())
     565           0 :         return true;
     566             : 
     567             :     // Async Iteration proposal 6.1.2 %AsyncIteratorPrototype%.
     568           0 :     RootedObject asyncIterProto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
     569           0 :     if (!asyncIterProto)
     570           0 :         return false;
     571           0 :     if (!DefinePropertiesAndFunctions(cx, asyncIterProto, nullptr, async_iterator_proto_methods))
     572           0 :         return false;
     573             : 
     574             :     // Async Iteration proposal 6.1.3.2 %AsyncFromSyncIteratorPrototype%.
     575             :     RootedObject asyncFromSyncIterProto(
     576           0 :         cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
     577           0 :                                                          asyncIterProto));
     578           0 :     if (!asyncFromSyncIterProto)
     579           0 :         return false;
     580           0 :     if (!DefinePropertiesAndFunctions(cx, asyncFromSyncIterProto, nullptr,
     581           0 :                                       async_from_sync_iter_methods) ||
     582           0 :         !DefineToStringTag(cx, asyncFromSyncIterProto, cx->names().AsyncFromSyncIterator))
     583             :     {
     584           0 :         return false;
     585             :     }
     586             : 
     587             :     // Async Iteration proposal 6.4.1 %AsyncGeneratorPrototype%.
     588             :     RootedObject asyncGenProto(
     589           0 :         cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
     590           0 :                                                          asyncIterProto));
     591           0 :     if (!asyncGenProto)
     592           0 :         return false;
     593           0 :     if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr, async_generator_methods) ||
     594           0 :         !DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator))
     595             :     {
     596           0 :         return false;
     597             :     }
     598             : 
     599             :     // Async Iteration proposal 6.3.3 %AsyncGenerator%.
     600           0 :     RootedObject asyncGenerator(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
     601           0 :     if (!asyncGenerator)
     602           0 :         return false;
     603           0 :     if (!JSObject::setDelegate(cx, asyncGenerator))
     604           0 :         return false;
     605           0 :     if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto, JSPROP_READONLY,
     606           0 :                                      JSPROP_READONLY) ||
     607           0 :         !DefineToStringTag(cx, asyncGenerator, cx->names().AsyncGeneratorFunction))
     608             :     {
     609           0 :         return false;
     610             :     }
     611             : 
     612           0 :     RootedValue function(cx, global->getConstructor(JSProto_Function));
     613           0 :     if (!function.toObjectOrNull())
     614           0 :         return false;
     615           0 :     RootedObject proto(cx, &function.toObject());
     616           0 :     RootedAtom name(cx, cx->names().AsyncGeneratorFunction);
     617             : 
     618             :     // Async Iteration proposal 6.3.2 %AsyncGeneratorFunction%.
     619             :     RootedObject asyncGenFunction(
     620           0 :         cx, NewFunctionWithProto(cx, AsyncGeneratorConstructor, 1, JSFunction::NATIVE_CTOR,
     621           0 :                                  nullptr, name, proto, gc::AllocKind::FUNCTION, SingletonObject));
     622           0 :     if (!asyncGenFunction)
     623           0 :         return false;
     624           0 :     if (!LinkConstructorAndPrototype(cx, asyncGenFunction, asyncGenerator,
     625           0 :                                      JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
     626             :     {
     627           0 :         return false;
     628             :     }
     629             : 
     630           0 :     global->setReservedSlot(ASYNC_ITERATOR_PROTO, ObjectValue(*asyncIterProto));
     631           0 :     global->setReservedSlot(ASYNC_FROM_SYNC_ITERATOR_PROTO, ObjectValue(*asyncFromSyncIterProto));
     632           0 :     global->setReservedSlot(ASYNC_GENERATOR, ObjectValue(*asyncGenerator));
     633           0 :     global->setReservedSlot(ASYNC_GENERATOR_FUNCTION, ObjectValue(*asyncGenFunction));
     634           0 :     global->setReservedSlot(ASYNC_GENERATOR_PROTO, ObjectValue(*asyncGenProto));
     635           0 :     return true;
     636             : }

Generated by: LCOV version 1.13