diff options
Diffstat (limited to 'js/src/builtin')
-rw-r--r-- | js/src/builtin/AsyncIteration.js | 7 | ||||
-rw-r--r-- | js/src/builtin/Promise.cpp | 738 | ||||
-rw-r--r-- | js/src/builtin/Promise.h | 22 | ||||
-rw-r--r-- | js/src/builtin/ReflectParse.cpp | 20 |
4 files changed, 653 insertions, 134 deletions
diff --git a/js/src/builtin/AsyncIteration.js b/js/src/builtin/AsyncIteration.js new file mode 100644 index 000000000..029c7c0f8 --- /dev/null +++ b/js/src/builtin/AsyncIteration.js @@ -0,0 +1,7 @@ +/* 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/. */ + +function AsyncIteratorIdentity() { + return this; +} diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 1d068f8c6..4900a91cb 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -11,11 +11,13 @@ #include "mozilla/TimeStamp.h" #include "jscntxt.h" +#include "jsexn.h" +#include "jsiter.h" #include "gc/Heap.h" #include "js/Debug.h" #include "vm/AsyncFunction.h" -#include "vm/SelfHosting.h" +#include "vm/AsyncIteration.h" #include "jsobjinlines.h" @@ -31,10 +33,34 @@ MillisecondsSinceStartup() return (now - mozilla::TimeStamp::ProcessCreation(ignored)).ToMilliseconds(); } -#define PROMISE_HANDLER_IDENTITY 0 -#define PROMISE_HANDLER_THROWER 1 -#define PROMISE_HANDLER_AWAIT_FULFILLED 2 -#define PROMISE_HANDLER_AWAIT_REJECTED 3 +enum PromiseHandler { + PromiseHandlerIdentity = 0, + PromiseHandlerThrower, + + // ES 2018 draft 25.5.5.4-5. + PromiseHandlerAsyncFunctionAwaitedFulfilled, + PromiseHandlerAsyncFunctionAwaitedRejected, + + // Async Iteration proposal 4.1. + PromiseHandlerAsyncGeneratorAwaitedFulfilled, + PromiseHandlerAsyncGeneratorAwaitedRejected, + + // Async Iteration proposal 11.4.3.5.1-2. + PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled, + PromiseHandlerAsyncGeneratorResumeNextReturnRejected, + + // Async Iteration proposal 11.4.3.7 steps 8.c-e. + PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled, + PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected, + + // Async Iteration proposal 11.1.3.2.5. + // Async-from-Sync iterator handlers take the resolved value and create new + // iterator objects. To do so it needs to forward whether the iterator is + // done. In spec, this is achieved via the [[Done]] internal slot. We + // enumerate both true and false cases here. + PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone, + PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone, +}; enum ResolutionMode { ResolveMode, @@ -47,9 +73,8 @@ enum ResolveFunctionSlots { }; enum RejectFunctionSlots { - RejectFunctionSlot_Promise = ResolveFunctionSlot_Promise, + RejectFunctionSlot_Promise = 0, RejectFunctionSlot_ResolveFunction, - RejectFunctionSlot_PromiseAllData = RejectFunctionSlot_ResolveFunction, }; enum PromiseAllResolveElementFunctionSlots { @@ -86,7 +111,7 @@ class PromiseAllDataHolder : public NativeObject static const Class class_; JSObject* promiseObj() { return &getFixedSlot(PromiseAllDataHolderSlot_Promise).toObject(); } JSObject* resolveObj() { - return getFixedSlot(PromiseAllDataHolderSlot_ResolveFunction).toObjectOrNull(); + return &getFixedSlot(PromiseAllDataHolderSlot_ResolveFunction).toObject(); } Value valuesArray() { return getFixedSlot(PromiseAllDataHolderSlot_ValuesArray); } int32_t remainingCount() { @@ -126,7 +151,7 @@ NewPromiseAllDataHolder(JSContext* cx, HandleObject resultPromise, HandleValue v dataHolder->setFixedSlot(PromiseAllDataHolderSlot_Promise, ObjectValue(*resultPromise)); dataHolder->setFixedSlot(PromiseAllDataHolderSlot_RemainingElements, Int32Value(1)); dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ValuesArray, valuesArray); - dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ResolveFunction, ObjectOrNullValue(resolve)); + dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ResolveFunction, ObjectValue(*resolve)); return dataHolder; } @@ -177,13 +202,15 @@ enum ReactionRecordSlots { ReactionRecordSlot_IncumbentGlobalObject, ReactionRecordSlot_Flags, ReactionRecordSlot_HandlerArg, + ReactionRecordSlot_Generator, ReactionRecordSlots, }; #define REACTION_FLAG_RESOLVED 0x1 #define REACTION_FLAG_FULFILLED 0x2 #define REACTION_FLAG_IGNORE_DEFAULT_RESOLUTION 0x4 -#define REACTION_FLAG_AWAIT 0x8 +#define REACTION_FLAG_ASYNC_FUNCTION 0x8 +#define REACTION_FLAG_ASYNC_GENERATOR 0x10 // ES2016, 25.4.1.2. class PromiseReactionRecord : public NativeObject @@ -210,14 +237,30 @@ class PromiseReactionRecord : public NativeObject flags |= REACTION_FLAG_FULFILLED; setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags)); } - void setIsAwait() { + void setIsAsyncFunction() { + int32_t flags = this->flags(); + flags |= REACTION_FLAG_ASYNC_FUNCTION; + setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags)); + } + bool isAsyncFunction() { int32_t flags = this->flags(); - flags |= REACTION_FLAG_AWAIT; + return flags & REACTION_FLAG_ASYNC_FUNCTION; + } + void setIsAsyncGenerator(Handle<AsyncGeneratorObject*> asyncGenObj) { + int32_t flags = this->flags(); + flags |= REACTION_FLAG_ASYNC_GENERATOR; setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags)); + + setFixedSlot(ReactionRecordSlot_Generator, ObjectValue(*asyncGenObj)); } - bool isAwait() { + bool isAsyncGenerator() { int32_t flags = this->flags(); - return flags & REACTION_FLAG_AWAIT; + return flags & REACTION_FLAG_ASYNC_GENERATOR; + } + AsyncGeneratorObject* asyncGenerator() { + MOZ_ASSERT(isAsyncGenerator()); + return &getFixedSlot(ReactionRecordSlot_Generator).toObject() + .as<AsyncGeneratorObject>(); } Value handler() { MOZ_ASSERT(targetState() != JS::PromiseState::Pending); @@ -277,12 +320,6 @@ CreateResolvingFunctions(JSContext* cx, HandleValue promise, if (!reject) return false; - // TODO: remove this once all self-hosted promise code is gone. - // The resolving functions are trusted, so self-hosted code should be able - // to call them using callFunction instead of callContentFunction. - resolve->setFlags(resolve->flags() | JSFunction::SELF_HOSTED); - reject->setFlags(reject->flags() | JSFunction::SELF_HOSTED); - resolve->setExtendedSlot(ResolveFunctionSlot_Promise, promise); resolve->setExtendedSlot(ResolveFunctionSlot_RejectFunction, ObjectValue(*reject)); @@ -319,28 +356,27 @@ RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp) return true; } + // Step 5. + // Here, we only remove the Promise reference from the resolution + // functions. Actually marking it as fulfilled/rejected happens later. + ClearResolutionFunctionSlots(reject); + RootedObject promise(cx, &promiseVal.toObject()); // In some cases the Promise reference on the resolution function won't // have been removed during resolution, so we need to check that here, // too. if (promise->is<PromiseObject>() && - PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_RESOLVED)) + promise->as<PromiseObject>().state() != JS::PromiseState::Pending) { - args.rval().setUndefined(); return true; } - // Step 5. - // Here, we only remove the Promise reference from the resolution - // functions. Actually marking it as fulfilled/rejected happens later. - ClearResolutionFunctionSlots(reject); - // Step 6. - bool result = RejectMaybeWrappedPromise(cx, promise, reasonVal); - if (result) - args.rval().setUndefined(); - return result; + if (!RejectMaybeWrappedPromise(cx, promise, reasonVal)) + return false; + args.rval().setUndefined(); + return true; } static MOZ_MUST_USE bool FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, @@ -351,16 +387,28 @@ static MOZ_MUST_USE bool EnqueuePromiseResolveThenableJob(JSContext* cx, HandleValue thenable, HandleValue thenVal); -// ES2016, 25.4.1.3.2, steps 7-13. +// ES2016, 25.4.1.3.2, steps 6-13. static MOZ_MUST_USE bool ResolvePromiseInternal(JSContext* cx, HandleObject promise, HandleValue resolutionVal) { - // Step 7. + // Step 7 (reordered). if (!resolutionVal.isObject()) return FulfillMaybeWrappedPromise(cx, promise, resolutionVal); RootedObject resolution(cx, &resolutionVal.toObject()); + // Step 6. + if (resolution == promise) { + // Step 6.a. + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF); + RootedValue selfResolutionError(cx); + MOZ_ALWAYS_TRUE(GetAndClearException(cx, &selfResolutionError)); + + // Step 6.b. + return RejectMaybeWrappedPromise(cx, promise, selfResolutionError); + } + // Step 8. RootedValue thenVal(cx); bool status = GetProperty(cx, resolution, resolution, cx->names().then, &thenVal); @@ -398,10 +446,7 @@ ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp) RootedFunction resolve(cx, &args.callee().as<JSFunction>()); RootedValue resolutionVal(cx, args.get(0)); - // Steps 1-2. - RootedValue promiseVal(cx, resolve->getExtendedSlot(ResolveFunctionSlot_Promise)); - - // Steps 3-4. + // Steps 3-4 (reordered). // We use the reference to the reject function as a signal for whether // the resolve or reject function was already called, at which point // the references on each of the functions are cleared. @@ -410,43 +455,28 @@ ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp) return true; } - RootedObject promise(cx, &promiseVal.toObject()); + // Steps 1-2 (reordered). + RootedObject promise(cx, &resolve->getExtendedSlot(ResolveFunctionSlot_Promise).toObject()); + + // Step 5. + // Here, we only remove the Promise reference from the resolution + // functions. Actually marking it as fulfilled/rejected happens later. + ClearResolutionFunctionSlots(resolve); // In some cases the Promise reference on the resolution function won't // have been removed during resolution, so we need to check that here, // too. if (promise->is<PromiseObject>() && - PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_RESOLVED)) + promise->as<PromiseObject>().state() != JS::PromiseState::Pending) { - args.rval().setUndefined(); return true; } - // Step 5. - // Here, we only remove the Promise reference from the resolution - // functions. Actually marking it as fulfilled/rejected happens later. - ClearResolutionFunctionSlots(resolve); - - // Step 6. - if (resolutionVal == promiseVal) { - // Step 6.a. - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF); - RootedValue selfResolutionError(cx); - bool status = GetAndClearException(cx, &selfResolutionError); - MOZ_ASSERT(status); - - // Step 6.b. - status = RejectMaybeWrappedPromise(cx, promise, selfResolutionError); - if (status) - args.rval().setUndefined(); - return status; - } - - bool status = ResolvePromiseInternal(cx, promise, resolutionVal); - if (status) - args.rval().setUndefined(); - return status; + // Steps 6-13. + if (!ResolvePromiseInternal(cx, promise, resolutionVal)) + return false; + args.rval().setUndefined(); + return true; } static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp); @@ -652,7 +682,7 @@ enum GetCapabilitiesExecutorSlots { }; static MOZ_MUST_USE PromiseObject* -CreatePromiseObjectWithDefaultResolution(JSContext* cx) +CreatePromiseObjectWithoutResolutionFunctions(JSContext* cx) { Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx)); if (!promise) @@ -687,7 +717,7 @@ NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise, // in the list passed to all/race, which (potentially) means exposing them // to content. if (canOmitResolutionFunctions && IsNativeFunction(cVal, PromiseConstructor)) { - promise.set(CreatePromiseObjectWithDefaultResolution(cx)); + promise.set(CreatePromiseObjectWithoutResolutionFunctions(cx)); if (!promise) return false; return true; @@ -795,9 +825,7 @@ RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue re // interpreter frame active right now. If a thenable job with a // throwing `then` function got us here, that'll not be the case, // so we add one by throwing the error from self-hosted code. - FixedInvokeArgs<1> getErrorArgs(cx); - getErrorArgs[0].set(Int32Value(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON)); - if (!CallSelfHostedFunction(cx, "GetInternalError", reason, getErrorArgs, &reason)) + if (!GetInternalError(cx, JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON, &reason)) return false; } } @@ -832,10 +860,10 @@ TriggerPromiseReactions(JSContext* cx, HandleValue reactionsVal, JS::PromiseStat } static MOZ_MUST_USE bool -AwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction, - MutableHandleValue rval) +AsyncFunctionPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction, + MutableHandleValue rval) { - MOZ_ASSERT(reaction->isAwait()); + MOZ_ASSERT(reaction->isAsyncFunction()); RootedValue handlerVal(cx, reaction->handler()); RootedValue argument(cx, reaction->handlerArg()); @@ -843,15 +871,14 @@ AwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction, RootedValue generatorVal(cx, resultPromise->getFixedSlot(PromiseSlot_AwaitGenerator)); int32_t handlerNum = int32_t(handlerVal.toNumber()); - MOZ_ASSERT(handlerNum == PROMISE_HANDLER_AWAIT_FULFILLED - || handlerNum == PROMISE_HANDLER_AWAIT_REJECTED); // Await's handlers don't return a value, nor throw exception. // They fail only on OOM. - if (handlerNum == PROMISE_HANDLER_AWAIT_FULFILLED) { + if (handlerNum == PromiseHandlerAsyncFunctionAwaitedFulfilled) { if (!AsyncFunctionAwaitedFulfilled(cx, resultPromise, generatorVal, argument)) return false; } else { + MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFunctionAwaitedRejected); if (!AsyncFunctionAwaitedRejected(cx, resultPromise, generatorVal, argument)) return false; } @@ -860,6 +887,55 @@ AwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction, return true; } +static MOZ_MUST_USE bool +AsyncGeneratorPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction, + MutableHandleValue rval) +{ + MOZ_ASSERT(reaction->isAsyncGenerator()); + + RootedValue handlerVal(cx, reaction->handler()); + RootedValue argument(cx, reaction->handlerArg()); + Rooted<AsyncGeneratorObject*> asyncGenObj(cx, reaction->asyncGenerator()); + + int32_t handlerNum = int32_t(handlerVal.toNumber()); + + // Await's handlers don't return a value, nor throw exception. + // They fail only on OOM. + if (handlerNum == PromiseHandlerAsyncGeneratorAwaitedFulfilled) { + // 4.1.1. + if (!AsyncGeneratorAwaitedFulfilled(cx, asyncGenObj, argument)) + return false; + } else if (handlerNum == PromiseHandlerAsyncGeneratorAwaitedRejected) { + // 4.1.2. + if (!AsyncGeneratorAwaitedRejected(cx, asyncGenObj, argument)) + return false; + } else if (handlerNum == PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled) { + asyncGenObj->setCompleted(); + // 11.4.3.5.1 step 1. + if (!AsyncGeneratorResolve(cx, asyncGenObj, argument, true)) + return false; + } else if (handlerNum == PromiseHandlerAsyncGeneratorResumeNextReturnRejected) { + asyncGenObj->setCompleted(); + // 11.4.3.5.2 step 1. + if (!AsyncGeneratorReject(cx, asyncGenObj, argument)) + return false; + } else if (handlerNum == PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled) { + asyncGenObj->setExecuting(); + // 11.4.3.7 steps 8.d-e. + if (!AsyncGeneratorYieldReturnAwaitedFulfilled(cx, asyncGenObj, argument)) + return false; + } else { + MOZ_ASSERT(handlerNum == PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected); + asyncGenObj->setExecuting(); + // 11.4.3.7 step 8.c. + if (!AsyncGeneratorYieldReturnAwaitedRejected(cx, asyncGenObj, argument)) + return false; + } + + rval.setUndefined(); + return true; +} + // ES2016, 25.4.2.1. /** * Callback triggering the fulfill/reject reaction for a resolved Promise, @@ -903,8 +979,10 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp) // Steps 1-2. Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>()); - if (reaction->isAwait()) - return AwaitPromiseReactionJob(cx, reaction, args.rval()); + if (reaction->isAsyncFunction()) + return AsyncFunctionPromiseReactionJob(cx, reaction, args.rval()); + if (reaction->isAsyncGenerator()) + return AsyncGeneratorPromiseReactionJob(cx, reaction, args.rval()); // Step 3. RootedValue handlerVal(cx, reaction->handler()); @@ -919,13 +997,23 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp) int32_t handlerNum = int32_t(handlerVal.toNumber()); // Step 4. - if (handlerNum == PROMISE_HANDLER_IDENTITY) { + if (handlerNum == PromiseHandlerIdentity) { handlerResult = argument; - } else { + } else if (handlerNum == PromiseHandlerThrower) { // Step 5. - MOZ_ASSERT(handlerNum == PROMISE_HANDLER_THROWER); resolutionMode = RejectMode; handlerResult = argument; + } else { + MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone || + handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone); + + bool done = handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone; + // Async Iteration proposal 11.1.3.2.5 step 1. + RootedObject resultObj(cx, CreateIterResultObject(cx, argument, done)); + if (!resultObj) + return false; + + handlerResult = ObjectValue(*resultObj); } } else { // Step 6. @@ -964,8 +1052,8 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp) * * Usage of the function's extended slots is as follows: * ThenableJobSlot_Handler: The handler to use as the Promise reaction. - * This can be PROMISE_HANDLER_IDENTITY, - * PROMISE_HANDLER_THROWER, or a callable. In the + * This can be PromiseHandlerIdentity, + * PromiseHandlerThrower, or a callable. In the * latter case, it's guaranteed to be an object * from the same compartment as the * PromiseReactionJob. @@ -1100,11 +1188,17 @@ GetResolveFunctionFromReject(JSFunction* reject) { MOZ_ASSERT(reject->maybeNative() == RejectPromiseFunction); Value resolveFunVal = reject->getExtendedSlot(RejectFunctionSlot_ResolveFunction); - if (IsNativeFunction(resolveFunVal, ResolvePromiseFunction)) - return &resolveFunVal.toObject().as<JSFunction>(); + MOZ_ASSERT(IsNativeFunction(resolveFunVal, ResolvePromiseFunction)); + return &resolveFunVal.toObject().as<JSFunction>(); +} - PromiseAllDataHolder* resolveFunObj = &resolveFunVal.toObject().as<PromiseAllDataHolder>(); - return &resolveFunObj->resolveObj()->as<JSFunction>(); +static JSFunction* +GetRejectFunctionFromResolve(JSFunction* resolve) +{ + MOZ_ASSERT(resolve->maybeNative() == ResolvePromiseFunction); + Value rejectFunVal = resolve->getExtendedSlot(ResolveFunctionSlot_RejectFunction); + MOZ_ASSERT(IsNativeFunction(rejectFunVal, RejectPromiseFunction)); + return &rejectFunVal.toObject().as<JSFunction>(); } static JSFunction* @@ -1140,8 +1234,7 @@ ClearResolutionFunctionSlots(JSFunction* resolutionFun) JSFunction* reject; if (resolutionFun->maybeNative() == ResolvePromiseFunction) { resolve = resolutionFun; - reject = &resolutionFun->getExtendedSlot(ResolveFunctionSlot_RejectFunction) - .toObject().as<JSFunction>(); + reject = GetRejectFunctionFromResolve(resolutionFun); } else { resolve = GetResolveFunctionFromReject(resolutionFun); reject = resolutionFun; @@ -1367,6 +1460,14 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto / return promise; } +// ES2016, 25.4.3.1. skipping creation of resolution functions and executor +// function invocation. +/* static */ PromiseObject* +PromiseObject::createSkippingExecutor(JSContext* cx) +{ + return CreatePromiseObjectWithoutResolutionFunctions(cx); +} + static MOZ_MUST_USE bool PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, HandleObject promiseObj, HandleObject resolve, HandleObject reject, @@ -1585,7 +1686,6 @@ RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue res if (promise->state() != JS::PromiseState::Pending) return true; - if (mode == ResolveMode) { if (!PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION)) return true; @@ -1595,7 +1695,6 @@ RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue res if (!PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_REJECT_FUNCTION)) return true; return RejectMaybeWrappedPromise(cx, promiseObj, result); - } // ES2016, 25.4.4.1.1. @@ -1669,7 +1768,7 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, // Step 6. RootedValue nextValue(cx); RootedId indexId(cx); - RootedValue rejectFunVal(cx, ObjectOrNullValue(reject)); + RootedValue rejectFunVal(cx, ObjectValue(*reject)); while (true) { // Steps a-c, e-g. @@ -1690,11 +1789,8 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, // Steps d.iii-iv. if (remainingCount == 0) { - if (resolve) { - return RunResolutionFunction(cx, resolve, valuesArrayVal, ResolveMode, - promiseObj); - } - return ResolvePromiseInternal(cx, promiseObj, valuesArrayVal); + return RunResolutionFunction(cx, resolve, valuesArrayVal, ResolveMode, + promiseObj); } // We're all set for now! @@ -1817,13 +1913,8 @@ PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp) // Step 6 (Adapted to work with PromiseAllDataHolder's layout). RootedObject resolveAllFun(cx, data->resolveObj()); RootedObject promiseObj(cx, data->promiseObj()); - if (!resolveAllFun) { - if (!FulfillMaybeWrappedPromise(cx, promiseObj, valuesVal)) - return false; - } else { - if (!RunResolutionFunction(cx, resolveAllFun, valuesVal, ResolveMode, promiseObj)) - return false; - } + if (!RunResolutionFunction(cx, resolveAllFun, valuesVal, ResolveMode, promiseObj)) + return false; } // Step 11. @@ -1904,8 +1995,8 @@ PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, RootedValue CVal(cx, ObjectValue(*C)); RootedValue nextValue(cx); - RootedValue resolveFunVal(cx, ObjectOrNullValue(resolve)); - RootedValue rejectFunVal(cx, ObjectOrNullValue(reject)); + RootedValue resolveFunVal(cx, ObjectValue(*resolve)); + RootedValue rejectFunVal(cx, ObjectValue(*reject)); while (true) { // Steps a-c, e-g. @@ -2155,12 +2246,12 @@ static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx, // Some async/await functions are implemented here instead of // js/src/builtin/AsyncFunction.cpp, to call Promise internal functions. -// Async Functions proposal 1.1.8 and 1.2.14 step 1. +// ES 2018 draft 14.6.11 and 14.7.14 step 1. MOZ_MUST_USE PromiseObject* js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal) { // Step 1. - Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithDefaultResolution(cx)); + Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx)); if (!promise) return nullptr; @@ -2169,7 +2260,7 @@ js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal) return promise; } -// Async Functions proposal 2.2 steps 3.f, 3.g. +// ES 2018 draft 25.5.5.2 steps 3.f, 3.g. MOZ_MUST_USE bool js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise) { @@ -2185,7 +2276,7 @@ js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise) return true; } -// Async Functions proposal 2.2 steps 3.d-e, 3.g. +// ES 2018 draft 25.5.5.2 steps 3.d-e, 3.g. MOZ_MUST_USE bool js::AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value) { @@ -2197,28 +2288,30 @@ js::AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, H return true; } -// Async Functions proposal 2.3 steps 2-8. -MOZ_MUST_USE bool -js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value) +// Helper function that performs the equivalent steps as +// Async Iteration proposal 4.1 Await steps 2-3, 6-9 or similar. +template <typename T> +static MOZ_MUST_USE bool +InternalAwait(JSContext* cx, HandleValue value, HandleObject resultPromise, + HandleValue onFulfilled, HandleValue onRejected, T extraStep) { + MOZ_ASSERT(onFulfilled.isNumber() || onFulfilled.isObject()); + MOZ_ASSERT(onRejected.isNumber() || onRejected.isObject()); + // Step 2. - Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithDefaultResolution(cx)); + Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx)); if (!promise) return false; - // Steps 3. + // Step 3. if (!ResolvePromiseInternal(cx, promise, value)) return false; - // Steps 4-5. - RootedValue onFulfilled(cx, Int32Value(PROMISE_HANDLER_AWAIT_FULFILLED)); - RootedValue onRejected(cx, Int32Value(PROMISE_HANDLER_AWAIT_REJECTED)); - RootedObject incumbentGlobal(cx); if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal)) return false; - // Steps 6-7. + // Steps 7-8. Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled, onRejected, nullptr, nullptr, @@ -2226,12 +2319,403 @@ js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, Hand if (!reaction) return false; - reaction->setIsAwait(); + // Step 6. + extraStep(reaction); - // Step 8. + // Step 9. return PerformPromiseThenWithReaction(cx, promise, reaction); } +// ES 2018 draft 25.5.5.3 steps 2-10. +MOZ_MUST_USE bool +js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value) +{ + // Steps 4-5. + RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitedFulfilled)); + RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitedRejected)); + + // Steps 2-3, 6-10. + auto extra = [](Handle<PromiseReactionRecord*> reaction) { + reaction->setIsAsyncFunction(); + }; + return InternalAwait(cx, value, resultPromise, onFulfilled, onRejected, extra); +} + +// Async Iteration proposal 4.1 Await steps 2-9. +MOZ_MUST_USE bool +js::AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, + HandleValue value) +{ + // Steps 4-5. + RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitedFulfilled)); + RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitedRejected)); + + // Steps 2-3, 6-9. + auto extra = [&](Handle<PromiseReactionRecord*> reaction) { + reaction->setIsAsyncGenerator(asyncGenObj); + }; + return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra); +} + +// Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next +// Async Iteration proposal 11.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return +// Async Iteration proposal 11.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) { + // 11.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) { + // 11.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 { + // 11.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; + } + } + + // 11.1.3.2.1 steps 5-6 (partially). + // 11.1.3.2.2, 11.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); + + // 11.1.3.2.1 steps 5-6 (partially). + // 11.1.3.2.2, 11.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 11.1.3.2.1. + // For 11.1.3.2.2 and 11.1.3.2.3, steps 7-16 corresponds to steps 11-20. + + // Steps 7-8. + RootedValue doneVal(cx); + if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal)) + return AbruptRejectPromise(cx, args, resultPromise, nullptr); + bool done = ToBoolean(doneVal); + + // Steps 9-10. + RootedValue value(cx); + if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value)) + return AbruptRejectPromise(cx, args, resultPromise, nullptr); + + // Steps 13-14. + RootedValue onFulfilled(cx, Int32Value(done + ? PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone + : PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone)); + RootedValue onRejected(cx, Int32Value(PromiseHandlerThrower)); + + // Steps 11-12, 15. + auto extra = [](Handle<PromiseReactionRecord*> reaction) { + }; + if (!InternalAwait(cx, value, resultPromise, onFulfilled, onRejected, extra)) + return false; + + // Step 16. + args.rval().setObject(*resultPromise); + return true; +} + +static MOZ_MUST_USE bool +AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj); + +// Async Iteration proposal 11.4.3.3. +MOZ_MUST_USE bool +js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, + HandleValue value, bool done) +{ + // Step 1 (implicit). + + // Steps 2-3. + MOZ_ASSERT(!asyncGenObj->isQueueEmpty()); + + // Step 4. + Rooted<AsyncGeneratorRequest*> request( + cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj)); + if (!request) + return false; + + // Step 5. + RootedObject resultPromise(cx, request->promise()); + + // Step 6. + RootedObject resultObj(cx, CreateIterResultObject(cx, value, done)); + if (!resultObj) + return false; + + RootedValue resultValue(cx, ObjectValue(*resultObj)); + + // Step 7. + if (!ResolvePromiseInternal(cx, resultPromise, resultValue)) + return false; + + // Step 8. + if (!AsyncGeneratorResumeNext(cx, asyncGenObj)) + return false; + + // Step 9. + return true; +} + +// Async Iteration proposal 11.4.3.4. +MOZ_MUST_USE bool +js::AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, + HandleValue exception) +{ + // Step 1 (implicit). + + // Steps 2-3. + MOZ_ASSERT(!asyncGenObj->isQueueEmpty()); + + // Step 4. + Rooted<AsyncGeneratorRequest*> request( + cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj)); + if (!request) + return false; + + // Step 5. + RootedObject resultPromise(cx, request->promise()); + + // Step 6. + if (!RejectMaybeWrappedPromise(cx, resultPromise, exception)) + return false; + + // Step 7. + if (!AsyncGeneratorResumeNext(cx, asyncGenObj)) + return false; + + // Step 8. + return true; +} + +// Async Iteration proposal 11.4.3.5. +static MOZ_MUST_USE bool +AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj) +{ + // Step 1 (implicit). + + // Steps 2-3. + MOZ_ASSERT(!asyncGenObj->isExecuting()); + + // Step 4. + if (asyncGenObj->isAwaitingYieldReturn() || asyncGenObj->isAwaitingReturn()) + return true; + + // Steps 5-6. + if (asyncGenObj->isQueueEmpty()) + return true; + + // Steps 7-8. + Rooted<AsyncGeneratorRequest*> request( + cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj)); + if (!request) + return false; + + // Step 9. + CompletionKind completionKind = request->completionKind(); + + // Step 10. + if (completionKind != CompletionKind::Normal) { + // Step 10.a. + if (asyncGenObj->isSuspendedStart()) + asyncGenObj->setCompleted(); + + // Step 10.b. + if (asyncGenObj->isCompleted()) { + RootedValue value(cx, request->completionValue()); + + // Step 10.b.i. + if (completionKind == CompletionKind::Return) { + // Steps 10.b.i.1. + asyncGenObj->setAwaitingReturn(); + + // Steps 10.b.i.4-6 (reordered). + RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled)); + RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorResumeNextReturnRejected)); + + // Steps 10.b.i.2-3, 7-10. + auto extra = [&](Handle<PromiseReactionRecord*> reaction) { + reaction->setIsAsyncGenerator(asyncGenObj); + }; + return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra); + } + + // Step 10.b.ii.1. + MOZ_ASSERT(completionKind == CompletionKind::Throw); + + // Steps 10.b.ii.2-3. + return AsyncGeneratorReject(cx, asyncGenObj, value); + } + } else if (asyncGenObj->isCompleted()) { + // Step 11. + return AsyncGeneratorResolve(cx, asyncGenObj, UndefinedHandleValue, true); + } + + // Step 12. + MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield()); + + // Step 16 (reordered). + asyncGenObj->setExecuting(); + + RootedValue argument(cx, request->completionValue()); + + if (completionKind == CompletionKind::Return) { + // 11.4.3.7 AsyncGeneratorYield step 8.b-e. + // Since we don't have the place that handles return from yield + // inside the generator, handle the case here, with extra state + // State_AwaitingYieldReturn. + asyncGenObj->setAwaitingYieldReturn(); + + RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled)); + RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected)); + + auto extra = [&](Handle<PromiseReactionRecord*> reaction) { + reaction->setIsAsyncGenerator(asyncGenObj); + }; + return InternalAwait(cx, argument, nullptr, onFulfilled, onRejected, extra); + } + + // Steps 13-15, 17-21. + return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument); +} + +// Async Iteration proposal 11.4.3.6. +MOZ_MUST_USE bool +js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal, + CompletionKind completionKind, HandleValue completionValue, + MutableHandleValue result) +{ + // Step 1 (implicit). + + // Step 2. + RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx)); + if (!resultPromise) + return false; + + // Step 3. + if (!asyncGenVal.isObject() || !asyncGenVal.toObject().is<AsyncGeneratorObject>()) { + // Step 3.a. + RootedValue badGeneratorError(cx); + if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_GENERATOR, &badGeneratorError)) + return false; + + // Step 3.b. + if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError)) + return false; + + // Step 3.c. + result.setObject(*resultPromise); + return true; + } + + Rooted<AsyncGeneratorObject*> asyncGenObj( + cx, &asyncGenVal.toObject().as<AsyncGeneratorObject>()); + + // Step 5 (reordered). + Rooted<AsyncGeneratorRequest*> request( + cx, AsyncGeneratorRequest::create(cx, completionKind, completionValue, resultPromise)); + if (!request) + return false; + + // Steps 4, 6. + if (!AsyncGeneratorObject::enqueueRequest(cx, asyncGenObj, request)) + return false; + + // Step 7. + if (!asyncGenObj->isExecuting()) { + // Step 8. + if (!AsyncGeneratorResumeNext(cx, asyncGenObj)) + return false; + } + + // Step 9. + result.setObject(*resultPromise); + return true; +} + // ES2016, 25.4.5.3. bool js::Promise_then(JSContext* cx, unsigned argc, Value* vp) @@ -2291,12 +2775,12 @@ PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue on // Step 3. RootedValue onFulfilled(cx, onFulfilled_); if (!IsCallable(onFulfilled)) - onFulfilled = Int32Value(PROMISE_HANDLER_IDENTITY); + onFulfilled = Int32Value(PromiseHandlerIdentity); // Step 4. RootedValue onRejected(cx, onRejected_); if (!IsCallable(onRejected)) - onRejected = Int32Value(PROMISE_HANDLER_THROWER); + onRejected = Int32Value(PromiseHandlerThrower); RootedObject incumbentGlobal(cx); if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal)) @@ -2645,6 +3129,9 @@ PromiseObject::resolve(JSContext* cx, Handle<PromiseObject*> promise, HandleValu if (promise->state() != JS::PromiseState::Pending) return true; + if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION)) + return ResolvePromiseInternal(cx, promise, resolutionValue); + RootedObject resolveFun(cx, GetResolveFunctionFromPromise(promise)); RootedValue funVal(cx, ObjectValue(*resolveFun)); @@ -2668,6 +3155,9 @@ PromiseObject::reject(JSContext* cx, Handle<PromiseObject*> promise, HandleValue if (promise->state() != JS::PromiseState::Pending) return true; + if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_REJECT_FUNCTION)) + return RejectMaybeWrappedPromise(cx, promise, rejectionValue); + RootedValue funVal(cx, promise->getFixedSlot(PromiseSlot_RejectFunction)); MOZ_ASSERT(IsCallable(funVal)); diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index 6a6453e46..b04bd0e2a 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -44,6 +44,8 @@ class PromiseObject : public NativeObject static PromiseObject* create(JSContext* cx, HandleObject executor, HandleObject proto = nullptr, bool needsWrapping = false); + static PromiseObject* createSkippingExecutor(JSContext* cx); + static JSObject* unforgeableResolve(JSContext* cx, HandleValue value); static JSObject* unforgeableReject(JSContext* cx, HandleValue value); @@ -149,6 +151,26 @@ AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise); MOZ_MUST_USE bool AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value); +class AsyncGeneratorObject; + +MOZ_MUST_USE bool +AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value); + +MOZ_MUST_USE bool +AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, + HandleValue value, bool done); + +MOZ_MUST_USE bool +AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, + HandleValue exception); + +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()), diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 8e8bb2417..22c958d4c 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -2800,11 +2800,11 @@ ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst) LOCAL_ASSERT(next->isKind(PNK_SEMI) && next->pn_kid->isKind(PNK_YIELD) && - next->pn_kid->pn_left); + next->pn_kid->pn_kid); RootedValue body(cx); - return expression(next->pn_kid->pn_left, &body) && + return expression(next->pn_kid->pn_kid, &body) && builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst); } @@ -3146,7 +3146,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_YIELD_STAR: { - MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos)); + MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos)); RootedValue arg(cx); return expression(pn->pn_left, &arg) && @@ -3155,10 +3155,10 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_YIELD: { - MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos)); + MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos)); RootedValue arg(cx); - return optExpression(pn->pn_left, &arg) && + return optExpression(pn->pn_kid, &arg) && builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst); } @@ -3422,10 +3422,10 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst) RootedFunction func(cx, pn->pn_funbox->function()); GeneratorStyle generatorStyle = - pn->pn_funbox->isGenerator() - ? (pn->pn_funbox->isLegacyGenerator() - ? GeneratorStyle::Legacy - : GeneratorStyle::ES6) + pn->pn_funbox->isStarGenerator() + ? GeneratorStyle::ES6 + : pn->pn_funbox->isLegacyGenerator() + ? GeneratorStyle::Legacy : GeneratorStyle::None; bool isAsync = pn->pn_funbox->isAsync(); @@ -3480,7 +3480,7 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& ParseNode* pnstart = pnbody->pn_head; // Skip over initial yield in generator. - if (pnstart && pnstart->isKind(PNK_YIELD)) { + if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) { MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD); pnstart = pnstart->pn_next; } |