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 : }
|