mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-11-02 20:47:33 +09:00
Bug 1331092 - Part 2: Implement Async Generator except yield*.
Tag #1287
This commit is contained in:
parent
c8d569d1b8
commit
10b93afff4
23 changed files with 1015 additions and 55 deletions
564
js/src/vm/AsyncIteration.cpp
Normal file
564
js/src/vm/AsyncIteration.cpp
Normal file
|
|
@ -0,0 +1,564 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "vm/AsyncIteration.h"
|
||||
|
||||
#include "jsarray.h"
|
||||
#include "jscompartment.h"
|
||||
|
||||
#include "builtin/Promise.h"
|
||||
#include "vm/GeneratorObject.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
#define UNWRAPPED_ASYNC_WRAPPED_SLOT 1
|
||||
#define WRAPPED_ASYNC_UNWRAPPED_SLOT 0
|
||||
|
||||
// Async Iteration proposal 2.3.10 Runtime Semantics: EvaluateBody.
|
||||
static bool
|
||||
WrappedAsyncGenerator(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
RootedFunction wrapped(cx, &args.callee().as<JSFunction>());
|
||||
RootedValue unwrappedVal(cx, wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT));
|
||||
RootedFunction unwrapped(cx, &unwrappedVal.toObject().as<JSFunction>());
|
||||
RootedValue thisValue(cx, args.thisv());
|
||||
|
||||
// Step 1.
|
||||
RootedValue generatorVal(cx);
|
||||
InvokeArgs args2(cx);
|
||||
if (!args2.init(cx, argc))
|
||||
return false;
|
||||
for (size_t i = 0, len = argc; i < len; i++)
|
||||
args2[i].set(args[i]);
|
||||
if (!Call(cx, unwrappedVal, thisValue, args2, &generatorVal))
|
||||
return false;
|
||||
|
||||
// Step 2.
|
||||
Rooted<AsyncGeneratorObject*> asyncGenObj(
|
||||
cx, AsyncGeneratorObject::create(cx, wrapped, generatorVal));
|
||||
if (!asyncGenObj)
|
||||
return false;
|
||||
|
||||
// Step 3 (skipped).
|
||||
// Done in AsyncGeneratorObject::create and generator.
|
||||
|
||||
// Step 4.
|
||||
args.rval().setObject(*asyncGenObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
|
||||
{
|
||||
MOZ_ASSERT(unwrapped->isAsync());
|
||||
MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
|
||||
"%FunctionPrototype% fallback in NewFunctionWithProto().");
|
||||
|
||||
// Create a new function with AsyncGeneratorPrototype, reusing the name and
|
||||
// the length of `unwrapped`.
|
||||
|
||||
RootedAtom funName(cx, unwrapped->explicitName());
|
||||
uint16_t length;
|
||||
if (!JSFunction::getLength(cx, unwrapped, &length))
|
||||
return nullptr;
|
||||
|
||||
RootedFunction wrapped(cx, NewFunctionWithProto(cx, WrappedAsyncGenerator, length,
|
||||
JSFunction::NATIVE_FUN, nullptr,
|
||||
funName, proto,
|
||||
AllocKind::FUNCTION_EXTENDED,
|
||||
TenuredObject));
|
||||
if (!wrapped)
|
||||
return nullptr;
|
||||
|
||||
if (unwrapped->hasCompileTimeName())
|
||||
wrapped->setCompileTimeName(unwrapped->compileTimeName());
|
||||
|
||||
// Link them to each other to make GetWrappedAsyncGenerator and
|
||||
// GetUnwrappedAsyncGenerator work.
|
||||
unwrapped->setExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
|
||||
wrapped->setExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
|
||||
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::WrapAsyncGenerator(JSContext* cx, HandleFunction unwrapped)
|
||||
{
|
||||
RootedObject proto(cx, GlobalObject::getOrCreateAsyncGenerator(cx, cx->global()));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
return WrapAsyncGeneratorWithProto(cx, unwrapped, proto);
|
||||
}
|
||||
|
||||
bool
|
||||
js::IsWrappedAsyncGenerator(JSFunction* fun)
|
||||
{
|
||||
return fun->maybeNative() == WrappedAsyncGenerator;
|
||||
}
|
||||
|
||||
JSFunction*
|
||||
js::GetWrappedAsyncGenerator(JSFunction* unwrapped)
|
||||
{
|
||||
MOZ_ASSERT(unwrapped->isAsync());
|
||||
return &unwrapped->getExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
|
||||
}
|
||||
|
||||
JSFunction*
|
||||
js::GetUnwrappedAsyncGenerator(JSFunction* wrapped)
|
||||
{
|
||||
MOZ_ASSERT(IsWrappedAsyncGenerator(wrapped));
|
||||
JSFunction* unwrapped = &wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT)
|
||||
.toObject().as<JSFunction>();
|
||||
MOZ_ASSERT(unwrapped->isAsync());
|
||||
return unwrapped;
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
CompletionKind completionKind, HandleValue argument);
|
||||
|
||||
// Async Iteration proposal 5.1.1 Await Fulfilled Functions.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue value)
|
||||
{
|
||||
return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Normal, value);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 5.1.2 Await Rejected Functions.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue reason)
|
||||
{
|
||||
return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.1.2 AsyncGenerator.prototype.next.
|
||||
static bool
|
||||
AsyncGeneratorNext(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Steps 1-3.
|
||||
return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Normal, args.get(0),
|
||||
args.rval());
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.1.3 AsyncGenerator.prototype.return.
|
||||
static bool
|
||||
AsyncGeneratorReturn(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Steps 1-3.
|
||||
return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Return, args.get(0),
|
||||
args.rval());
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.1.4 AsyncGenerator.prototype.throw.
|
||||
static bool
|
||||
AsyncGeneratorThrow(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Steps 1-3.
|
||||
return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Throw, args.get(0),
|
||||
args.rval());
|
||||
}
|
||||
|
||||
const Class AsyncGeneratorObject::class_ = {
|
||||
"AsyncGenerator",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorObject::Slots)
|
||||
};
|
||||
|
||||
// ES 2017 draft 9.1.13.
|
||||
template <typename ProtoGetter>
|
||||
static JSObject*
|
||||
OrdinaryCreateFromConstructor(JSContext* cx, HandleFunction fun,
|
||||
ProtoGetter protoGetter, const Class* clasp)
|
||||
{
|
||||
// Step 1 (skipped).
|
||||
|
||||
// Step 2.
|
||||
RootedValue protoVal(cx);
|
||||
if (!GetProperty(cx, fun, fun, cx->names().prototype, &protoVal))
|
||||
return nullptr;
|
||||
|
||||
RootedObject proto(cx, protoVal.isObject() ? &protoVal.toObject() : nullptr);
|
||||
if (!proto) {
|
||||
proto = protoGetter(cx, cx->global());
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Step 3.
|
||||
return NewNativeObjectWithGivenProto(cx, clasp, proto);
|
||||
}
|
||||
|
||||
/* static */ AsyncGeneratorObject*
|
||||
AsyncGeneratorObject::create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal)
|
||||
{
|
||||
MOZ_ASSERT(generatorVal.isObject());
|
||||
MOZ_ASSERT(generatorVal.toObject().is<GeneratorObject>());
|
||||
|
||||
RootedObject obj(
|
||||
cx, OrdinaryCreateFromConstructor(cx, asyncGen,
|
||||
GlobalObject::getOrCreateAsyncGeneratorPrototype,
|
||||
&class_));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
Handle<AsyncGeneratorObject*> asyncGenObj = obj.as<AsyncGeneratorObject>();
|
||||
|
||||
// Async Iteration proposal 6.4.3.2 AsyncGeneratorStart.
|
||||
// Step 6.
|
||||
asyncGenObj->setGenerator(generatorVal);
|
||||
|
||||
// Step 7.
|
||||
asyncGenObj->setSuspendedStart();
|
||||
|
||||
// Step 8.
|
||||
asyncGenObj->clearSingleQueueRequest();
|
||||
|
||||
return asyncGenObj;
|
||||
}
|
||||
|
||||
/* static */ MOZ_MUST_USE bool
|
||||
AsyncGeneratorObject::enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
Handle<AsyncGeneratorRequest*> request)
|
||||
{
|
||||
if (asyncGenObj->isSingleQueue()) {
|
||||
if (asyncGenObj->isSingleQueueEmpty()) {
|
||||
asyncGenObj->setSingleQueueRequest(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedArrayObject queue(cx, NewDenseEmptyArray(cx));
|
||||
if (!queue)
|
||||
return false;
|
||||
|
||||
if (!NewbornArrayPush(cx, queue, ObjectValue(*asyncGenObj->singleQueueRequest())))
|
||||
return false;
|
||||
if (!NewbornArrayPush(cx, queue, ObjectValue(*request)))
|
||||
return false;
|
||||
|
||||
asyncGenObj->setQueue(queue);
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedArrayObject queue(cx, asyncGenObj->queue());
|
||||
|
||||
FixedInvokeArgs<1> args(cx);
|
||||
args[0].setObject(*request);
|
||||
args.setThis(ObjectValue(*queue));
|
||||
return CallJSNative(cx, array_push, args);
|
||||
}
|
||||
|
||||
/* static */ AsyncGeneratorRequest*
|
||||
AsyncGeneratorObject::dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
|
||||
{
|
||||
if (asyncGenObj->isSingleQueue()) {
|
||||
AsyncGeneratorRequest* request = asyncGenObj->singleQueueRequest();
|
||||
asyncGenObj->clearSingleQueueRequest();
|
||||
return request;
|
||||
}
|
||||
|
||||
RootedArrayObject queue(cx, asyncGenObj->queue());
|
||||
|
||||
FixedInvokeArgs<0> args(cx);
|
||||
args.setThis(ObjectValue(*queue));
|
||||
if (!CallJSNative(cx, array_shift, args))
|
||||
return nullptr;
|
||||
|
||||
return &args.rval().toObject().as<AsyncGeneratorRequest>();
|
||||
}
|
||||
|
||||
/* static */ AsyncGeneratorRequest*
|
||||
AsyncGeneratorObject::peekRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
|
||||
{
|
||||
if (asyncGenObj->isSingleQueue())
|
||||
return asyncGenObj->singleQueueRequest();
|
||||
|
||||
RootedArrayObject queue(cx, asyncGenObj->queue());
|
||||
|
||||
RootedValue requestVal(cx);
|
||||
if (!GetElement(cx, queue, queue, 0, &requestVal))
|
||||
return nullptr;
|
||||
|
||||
return &requestVal.toObject().as<AsyncGeneratorRequest>();
|
||||
}
|
||||
|
||||
const Class AsyncGeneratorRequest::class_ = {
|
||||
"AsyncGeneratorRequest",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorRequest::Slots)
|
||||
};
|
||||
|
||||
// Async Iteration proposal 6.4.3.1.
|
||||
/* static */ AsyncGeneratorRequest*
|
||||
AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind_,
|
||||
HandleValue completionValue_, HandleObject promise_)
|
||||
{
|
||||
RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, nullptr));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
Handle<AsyncGeneratorRequest*> request = obj.as<AsyncGeneratorRequest>();
|
||||
request->setCompletionKind(completionKind_);
|
||||
request->setCompletionValue(completionValue_);
|
||||
request->setPromise(promise_);
|
||||
return request;
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.3.2 steps 5.d-g.
|
||||
static MOZ_MUST_USE bool
|
||||
AsyncGeneratorReturned(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue value)
|
||||
{
|
||||
// Step 5.d.
|
||||
asyncGenObj->setCompleted();
|
||||
|
||||
// Step 5.e (done in bytecode).
|
||||
// Step 5.f.i (implicit).
|
||||
|
||||
// Step 5.g.
|
||||
return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.3.2 steps 5.d, f.
|
||||
static MOZ_MUST_USE bool
|
||||
AsyncGeneratorThrown(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
|
||||
{
|
||||
// Step 5.d.
|
||||
asyncGenObj->setCompleted();
|
||||
|
||||
// Not much we can do about uncatchable exceptions, so just bail.
|
||||
if (!cx->isExceptionPending())
|
||||
return false;
|
||||
|
||||
// Step 5.f.i.
|
||||
RootedValue value(cx);
|
||||
if (!GetAndClearException(cx, &value))
|
||||
return false;
|
||||
|
||||
// Step 5.f.ii.
|
||||
return AsyncGeneratorReject(cx, asyncGenObj, value);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.3.5.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
|
||||
{
|
||||
// Step 1 (implicit).
|
||||
|
||||
// Steps 2-3.
|
||||
MOZ_ASSERT(!asyncGenObj->isExecuting());
|
||||
|
||||
// Steps 4-5.
|
||||
if (asyncGenObj->isQueueEmpty())
|
||||
return true;
|
||||
|
||||
// Steps 6-7.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
// Step 8.
|
||||
CompletionKind completionKind = request->completionKind();
|
||||
|
||||
// Step 9.
|
||||
if (completionKind != CompletionKind::Normal) {
|
||||
// Step 9.a.
|
||||
if (asyncGenObj->isSuspendedStart())
|
||||
asyncGenObj->setCompleted();
|
||||
|
||||
// Step 9.b.
|
||||
if (asyncGenObj->isCompleted()) {
|
||||
// Step 9.b.i.
|
||||
RootedValue value(cx, request->completionValue());
|
||||
if (completionKind == CompletionKind::Return)
|
||||
return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
|
||||
// Step 9.b.ii.
|
||||
return AsyncGeneratorReject(cx, asyncGenObj, value);
|
||||
}
|
||||
} else if (asyncGenObj->isCompleted()) {
|
||||
// Step 10.
|
||||
return AsyncGeneratorResolve(cx, asyncGenObj, UndefinedHandleValue, true);
|
||||
}
|
||||
|
||||
// Step 11.
|
||||
MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield());
|
||||
|
||||
// Step 15 (reordered).
|
||||
asyncGenObj->setExecuting();
|
||||
|
||||
RootedValue argument(cx, request->completionValue());
|
||||
|
||||
// Steps 12-14, 16-20.
|
||||
return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.2.1.2 (partially).
|
||||
// Most steps are done in generator.
|
||||
static MOZ_MUST_USE bool
|
||||
AsyncGeneratorYield(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue value, bool done)
|
||||
{
|
||||
// Step 6.
|
||||
asyncGenObj->setSuspendedYield();
|
||||
|
||||
// Step 10.c.
|
||||
return AsyncGeneratorResolve(cx, asyncGenObj, value, done);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.3.5 steps 12-14, 16-20.
|
||||
// Async Iteration proposal 6.2.1.2 step 10.
|
||||
// Async Iteration proposal 6.4.3.2 step 5.f-g.
|
||||
// Async Iteration proposal 5.1 steps 2-9.
|
||||
// Execution context switching is handled in generator.
|
||||
static MOZ_MUST_USE bool
|
||||
AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
CompletionKind completionKind, HandleValue argument)
|
||||
{
|
||||
RootedValue generatorVal(cx, asyncGenObj->generatorVal());
|
||||
|
||||
// 6.4.3.5 steps 12-14, 16-20.
|
||||
HandlePropertyName funName = completionKind == CompletionKind::Normal
|
||||
? cx->names().StarGeneratorNext
|
||||
: completionKind == CompletionKind::Throw
|
||||
? cx->names().StarGeneratorThrow
|
||||
: cx->names().StarGeneratorReturn;
|
||||
FixedInvokeArgs<1> args(cx);
|
||||
args[0].set(argument);
|
||||
RootedValue result(cx);
|
||||
if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result)) {
|
||||
// 6.4.3.2 step 5.d, f.
|
||||
return AsyncGeneratorThrown(cx, asyncGenObj);
|
||||
}
|
||||
|
||||
// The following code corresponds to the following 3 cases:
|
||||
// * yield
|
||||
// * await
|
||||
// * return
|
||||
// For await 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.
|
||||
|
||||
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));
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
static const JSFunctionSpec async_iterator_proto_methods[] = {
|
||||
JS_SELF_HOSTED_SYM_FN(asyncIterator, "AsyncIteratorIdentity", 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
static const JSFunctionSpec async_generator_methods[] = {
|
||||
JS_FN("next", AsyncGeneratorNext, 1, 0),
|
||||
JS_FN("throw", AsyncGeneratorThrow, 1, 0),
|
||||
JS_FN("return", AsyncGeneratorReturn, 1, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
/* static */ MOZ_MUST_USE bool
|
||||
GlobalObject::initAsyncGenerators(JSContext* cx, Handle<GlobalObject*> global)
|
||||
{
|
||||
if (global->getReservedSlot(ASYNC_ITERATOR_PROTO).isObject())
|
||||
return true;
|
||||
|
||||
// Async Iteration proposal 6.1.2 %AsyncIteratorPrototype%.
|
||||
RootedObject asyncIterProto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
|
||||
if (!asyncIterProto)
|
||||
return false;
|
||||
if (!DefinePropertiesAndFunctions(cx, asyncIterProto, nullptr, async_iterator_proto_methods))
|
||||
return false;
|
||||
|
||||
// Async Iteration proposal 6.4.1 %AsyncGeneratorPrototype%.
|
||||
RootedObject asyncGenProto(
|
||||
cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
|
||||
asyncIterProto));
|
||||
if (!asyncGenProto)
|
||||
return false;
|
||||
if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr, async_generator_methods) ||
|
||||
!DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.3.3 %AsyncGenerator%.
|
||||
RootedObject asyncGenerator(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
|
||||
if (!asyncGenerator)
|
||||
return false;
|
||||
if (!JSObject::setDelegate(cx, asyncGenerator))
|
||||
return false;
|
||||
if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto, JSPROP_READONLY,
|
||||
JSPROP_READONLY) ||
|
||||
!DefineToStringTag(cx, asyncGenerator, cx->names().AsyncGeneratorFunction))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue function(cx, global->getConstructor(JSProto_Function));
|
||||
if (!function.toObjectOrNull())
|
||||
return false;
|
||||
RootedObject proto(cx, &function.toObject());
|
||||
RootedAtom name(cx, cx->names().AsyncGeneratorFunction);
|
||||
|
||||
// Async Iteration proposal 6.3.2 %AsyncGeneratorFunction%.
|
||||
RootedObject asyncGenFunction(
|
||||
cx, NewFunctionWithProto(cx, AsyncGeneratorConstructor, 1, JSFunction::NATIVE_CTOR,
|
||||
nullptr, name, proto, gc::AllocKind::FUNCTION, SingletonObject));
|
||||
if (!asyncGenFunction)
|
||||
return false;
|
||||
if (!LinkConstructorAndPrototype(cx, asyncGenFunction, asyncGenerator,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
global->setReservedSlot(ASYNC_ITERATOR_PROTO, ObjectValue(*asyncIterProto));
|
||||
global->setReservedSlot(ASYNC_GENERATOR, ObjectValue(*asyncGenerator));
|
||||
global->setReservedSlot(ASYNC_GENERATOR_FUNCTION, ObjectValue(*asyncGenFunction));
|
||||
global->setReservedSlot(ASYNC_GENERATOR_PROTO, ObjectValue(*asyncGenProto));
|
||||
return true;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue