author | André Bargull <andre.bargull@gmail.com> |
Mon, 25 Feb 2019 05:12:16 -0800 | |
changeset 461675 | 48fb1e2b6e97f1f089c259d4f3209ee26a274e74 |
parent 461674 | 135c13d4ceba69ab9b70c4803198b107c8f0cc06 |
child 461676 | b84fd1d91da2afcbd1d73bc16bc374fbe43c634c |
push id | 35626 |
push user | csabou@mozilla.com |
push date | Thu, 28 Feb 2019 11:31:08 +0000 |
treeherder | mozilla-central@2ea0c1db7e60 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | arai |
bugs | 1530324 |
milestone | 67.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -1475,33 +1475,30 @@ static MOZ_MUST_USE bool DefaultResolvin static MOZ_MUST_USE bool AsyncFunctionPromiseReactionJob( JSContext* cx, Handle<PromiseReactionRecord*> reaction, MutableHandleValue rval) { MOZ_ASSERT(reaction->isAsyncFunction()); RootedValue handlerVal(cx, reaction->handler()); RootedValue argument(cx, reaction->handlerArg()); - Rooted<PromiseObject*> resultPromise( - cx, &reaction->promise()->as<PromiseObject>()); Rooted<AsyncFunctionGeneratorObject*> generator( cx, reaction->asyncFunctionGenerator()); int32_t handlerNum = handlerVal.toInt32(); - // Await's handlers don't return a value, nor throw exception. + // Await's handlers don't return a value, nor throw an exception. // They fail only on OOM. if (handlerNum == PromiseHandlerAsyncFunctionAwaitedFulfilled) { - if (!AsyncFunctionAwaitedFulfilled(cx, resultPromise, generator, - argument)) { + if (!AsyncFunctionAwaitedFulfilled(cx, generator, argument)) { return false; } } else { MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFunctionAwaitedRejected); - if (!AsyncFunctionAwaitedRejected(cx, resultPromise, generator, argument)) { + if (!AsyncFunctionAwaitedRejected(cx, generator, argument)) { return false; } } rval.setUndefined(); return true; } @@ -3272,16 +3269,17 @@ static PromiseReactionRecord* NewReactio JSObject* unwrappedPromise = UncheckedUnwrap(resultCapability.promise()); MOZ_ASSERT(unwrappedPromise->is<PromiseObject>()); MOZ_ASSERT(!resultCapability.resolve()); MOZ_ASSERT(!resultCapability.reject()); } } else { // `resultCapability.promise` is null for the following cases: // * resulting Promise is known to be unused + // * Async Function // * Async Generator // In any case, other fields are also not used. MOZ_ASSERT(!resultCapability.resolve()); MOZ_ASSERT(!resultCapability.reject()); MOZ_ASSERT(incumbentGlobalObjectOption == IncumbentGlobalObject::Yes); } #endif @@ -3511,43 +3509,33 @@ MOZ_MUST_USE PromiseObject* js::CreatePr return promise; } bool js::IsPromiseForAsync(JSObject* promise) { return promise->is<PromiseObject>() && PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_ASYNC); } -// ES 2018 draft 25.5.5.2 steps 3.f, 3.g. +// ES2019 draft rev 7428c89bef626548084cd4e697a19ece7168f24c +// 25.7.5.1 AsyncFunctionStart, steps 3.f-g. MOZ_MUST_USE bool js::AsyncFunctionThrown( JSContext* cx, Handle<PromiseObject*> resultPromise) { - // Step 3.f. RootedValue exc(cx); if (!MaybeGetAndClearException(cx, &exc)) { return false; } - if (!RejectPromiseInternal(cx, resultPromise, exc)) { - return false; - } - - // Step 3.g. - return true; + return RejectPromiseInternal(cx, resultPromise, exc); } -// ES 2018 draft 25.5.5.2 steps 3.d-e, 3.g. +// ES2019 draft rev 7428c89bef626548084cd4e697a19ece7168f24c +// 25.7.5.1 AsyncFunctionStart, steps 3.d-e, 3.g. MOZ_MUST_USE bool js::AsyncFunctionReturned( JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value) { - // Steps 3.d-e. - if (!ResolvePromiseInternal(cx, resultPromise, value)) { - return false; - } - - // Step 3.g. - return true; + return ResolvePromiseInternal(cx, resultPromise, 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, @@ -3582,29 +3570,28 @@ static MOZ_MUST_USE bool InternalAwait(J // 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<AsyncFunctionGeneratorObject*> genObj, - Handle<PromiseObject*> resultPromise, HandleValue value) { + 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(genObj); }; - return InternalAwait(cx, value, resultPromise, onFulfilled, onRejected, - extra); + return InternalAwait(cx, value, nullptr, 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(
--- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -249,17 +249,17 @@ MOZ_MUST_USE bool AsyncFunctionReturned( Handle<PromiseObject*> resultPromise, HandleValue value); MOZ_MUST_USE bool AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise); MOZ_MUST_USE bool AsyncFunctionAwait( JSContext* cx, Handle<AsyncFunctionGeneratorObject*> genObj, - Handle<PromiseObject*> resultPromise, HandleValue value); + HandleValue value); // If the await operation can be skipped and the resolution value for `val` can // be acquired, stored the resolved value to `resolved` and `true` to // `*canSkip`. Otherwise, stores `false` to `*canSkip`. MOZ_MUST_USE bool TrySkipAwait(JSContext* cx, HandleValue val, bool* canSkip, MutableHandleValue resolved); class AsyncGeneratorObject;
--- a/js/src/jit-test/tests/debug/onEnterFrame-async-resumption-06.js +++ b/js/src/jit-test/tests/debug/onEnterFrame-async-resumption-06.js @@ -36,14 +36,14 @@ assertEq(hits, 1); drainJobQueue(); assertEq(hits, 1); let pw2 = gw.makeDebuggeeValue(p2); assertEq(pw2.isPromise, true); assertEq(pw2.promiseState, "fulfilled"); -assertEq(pw2.promiseValue, undefined); +assertEq(pw2.promiseValue, "moar ponies"); let pw = gw.makeDebuggeeValue(p); assertEq(pw.isPromise, true); assertEq(pw.promiseState, "fulfilled"); assertEq(pw.promiseValue, "moar ponies");
--- a/js/src/vm/AsyncFunction.cpp +++ b/js/src/vm/AsyncFunction.cpp @@ -10,16 +10,18 @@ #include "builtin/Promise.h" #include "vm/GeneratorObject.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" #include "vm/Realm.h" #include "vm/SelfHosting.h" +#include "vm/JSObject-inl.h" + using namespace js; using mozilla::Maybe; /* static */ bool GlobalObject::initAsyncFunction( JSContext* cx, Handle<GlobalObject*> global) { if (global->getReservedSlot(ASYNC_FUNCTION_PROTO).isObject()) { return true; @@ -55,18 +57,17 @@ using mozilla::Maybe; global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction)); global->setReservedSlot(ASYNC_FUNCTION_PROTO, ObjectValue(*asyncFunctionProto)); return true; } static MOZ_MUST_USE bool AsyncFunctionStart( - JSContext* cx, Handle<PromiseObject*> resultPromise, - Handle<AsyncFunctionGeneratorObject*> generator); + JSContext* cx, Handle<AsyncFunctionGeneratorObject*> generator); #define UNWRAPPED_ASYNC_WRAPPED_SLOT 1 #define WRAPPED_ASYNC_UNWRAPPED_SLOT 0 // Async Functions proposal 1.1.8 and 1.2.14. static bool WrappedAsyncFunction(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); @@ -87,31 +88,25 @@ static bool WrappedAsyncFunction(JSConte if (!generatorVal.isObject() || !generatorVal.toObject().is<AsyncFunctionGeneratorObject>()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE, "return value", JS::InformalValueTypeName(generatorVal)); return false; } - // Step 1. - Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectForAsync(cx)); - if (!resultPromise) { - return false; - } - // Step 3. Rooted<AsyncFunctionGeneratorObject*> generator( cx, &generatorVal.toObject().as<AsyncFunctionGeneratorObject>()); - if (!AsyncFunctionStart(cx, resultPromise, generator)) { + if (!AsyncFunctionStart(cx, generator)) { return false; } // Step 5. - args.rval().setObject(*resultPromise); + args.rval().setObject(*generator->promise()); return true; } if (!cx->isExceptionPending()) { return false; } // Steps 1, 4. @@ -186,32 +181,38 @@ JSObject* js::WrapAsyncFunction(JSContex enum class ResumeKind { Normal, Throw }; // Async Functions proposal 2.2 steps 3.f, 3.g. // Async Functions proposal 2.2 steps 3.d-e, 3.g. // Implemented in js/src/builtin/Promise.cpp // Async Functions proposal 2.2 steps 3-8, 2.4 steps 2-7, 2.5 steps 2-7. static bool AsyncFunctionResume(JSContext* cx, - Handle<PromiseObject*> resultPromise, Handle<AsyncFunctionGeneratorObject*> generator, ResumeKind kind, HandleValue valueOrReason) { - RootedObject stack(cx, resultPromise->allocationSite()); + Rooted<PromiseObject*> resultPromise(cx, generator->promise()); + + RootedObject stack(cx); Maybe<JS::AutoSetAsyncStackForNewCalls> asyncStack; - if (stack) { - asyncStack.emplace( - cx, stack, "async", - JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT); + if (JSObject* allocationSite = resultPromise->allocationSite()) { + // The promise is created within the activation of the async function, so + // use the parent frame as the starting point for async stacks. + stack = allocationSite->as<SavedFrame>().getParent(); + if (stack) { + asyncStack.emplace( + cx, stack, "async", + JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT); + } } // This case can only happen when the debugger force-returned the same // generator object for two async function calls. It doesn't matter how we // handle it, as long as we don't crash. if (generator->isClosed() || !generator->isSuspended()) { - return AsyncFunctionReturned(cx, resultPromise, UndefinedHandleValue); + return true; } // Execution context switching is handled in generator. HandlePropertyName funName = kind == ResumeKind::Normal ? cx->names().AsyncFunctionNext : cx->names().AsyncFunctionThrow; FixedInvokeArgs<1> args(cx); args[0].set(valueOrReason); @@ -220,53 +221,50 @@ static bool AsyncFunctionResume(JSContex &generatorOrValue)) { if (!generator->isClosed()) { generator->setClosed(); } return AsyncFunctionThrown(cx, resultPromise); } if (generator->isAfterAwait()) { - return AsyncFunctionAwait(cx, generator, resultPromise, generatorOrValue); + return AsyncFunctionAwait(cx, generator, generatorOrValue); } return AsyncFunctionReturned(cx, resultPromise, generatorOrValue); } // Async Functions proposal 2.2 steps 3-8. static MOZ_MUST_USE bool AsyncFunctionStart( - JSContext* cx, Handle<PromiseObject*> resultPromise, - Handle<AsyncFunctionGeneratorObject*> generator) { - return AsyncFunctionResume(cx, resultPromise, generator, ResumeKind::Normal, + JSContext* cx, Handle<AsyncFunctionGeneratorObject*> generator) { + return AsyncFunctionResume(cx, generator, ResumeKind::Normal, UndefinedHandleValue); } // Async Functions proposal 2.3 steps 1-8. // Implemented in js/src/builtin/Promise.cpp // Async Functions proposal 2.4. MOZ_MUST_USE bool js::AsyncFunctionAwaitedFulfilled( - JSContext* cx, Handle<PromiseObject*> resultPromise, - Handle<AsyncFunctionGeneratorObject*> generator, HandleValue value) { + JSContext* cx, Handle<AsyncFunctionGeneratorObject*> generator, + HandleValue value) { // Step 1 (implicit). // Steps 2-7. - return AsyncFunctionResume(cx, resultPromise, generator, ResumeKind::Normal, - value); + return AsyncFunctionResume(cx, generator, ResumeKind::Normal, value); } // Async Functions proposal 2.5. MOZ_MUST_USE bool js::AsyncFunctionAwaitedRejected( - JSContext* cx, Handle<PromiseObject*> resultPromise, - Handle<AsyncFunctionGeneratorObject*> generator, HandleValue reason) { + JSContext* cx, Handle<AsyncFunctionGeneratorObject*> generator, + HandleValue reason) { // Step 1 (implicit). // Step 2-7. - return AsyncFunctionResume(cx, resultPromise, generator, ResumeKind::Throw, - reason); + return AsyncFunctionResume(cx, generator, ResumeKind::Throw, reason); } JSFunction* js::GetWrappedAsyncFunction(JSFunction* unwrapped) { MOZ_ASSERT(unwrapped->isAsync()); return &unwrapped->getExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT) .toObject() .as<JSFunction>(); } @@ -279,8 +277,30 @@ JSFunction* js::GetUnwrappedAsyncFunctio .as<JSFunction>(); MOZ_ASSERT(unwrapped->isAsync()); return unwrapped; } bool js::IsWrappedAsyncFunction(JSFunction* fun) { return fun->maybeNative() == WrappedAsyncFunction; } + +const Class AsyncFunctionGeneratorObject::class_ = { + "AsyncFunctionGenerator", + JSCLASS_HAS_RESERVED_SLOTS(AsyncFunctionGeneratorObject::RESERVED_SLOTS)}; + +AsyncFunctionGeneratorObject* AsyncFunctionGeneratorObject::create( + JSContext* cx, HandleFunction fun) { + MOZ_ASSERT(fun->isAsync() && !fun->isGenerator()); + + Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectForAsync(cx)); + if (!resultPromise) { + return nullptr; + } + + auto* obj = NewBuiltinClassInstance<AsyncFunctionGeneratorObject>(cx); + if (!obj) { + return nullptr; + } + obj->initFixedSlot(PROMISE_SLOT, ObjectValue(*resultPromise)); + + return obj; +}
--- a/js/src/vm/AsyncFunction.h +++ b/js/src/vm/AsyncFunction.h @@ -2,23 +2,24 @@ * vim: set ts=8 sts=2 et sw=2 tw=80: * 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/. */ #ifndef vm_AsyncFunction_h #define vm_AsyncFunction_h +#include "builtin/Promise.h" +#include "js/Class.h" +#include "vm/GeneratorObject.h" #include "vm/JSContext.h" #include "vm/JSObject.h" namespace js { -class AsyncFunctionGeneratorObject; - // An async function is implemented using two function objects, which are // referred to as the "unwrapped" and the "wrapped" async function object. // The unwrapped function is a generator function compiled from the async // function's script. |await| expressions within the async function are // compiled like |yield| expression for the generator function with dedicated // opcode,. The unwrapped function is never exposed to user script. // The wrapped function is a native function which wraps the generator function, // hence its name, and is the publicly exposed object of the async function. @@ -40,22 +41,42 @@ bool IsWrappedAsyncFunction(JSFunction* // prototype object. JSObject* WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto); // Create a wrapped async function from unwrapped async function with default // prototype object. JSObject* WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped); +class AsyncFunctionGeneratorObject; + // Resume the async function when the `await` operand resolves. // Split into two functions depending on whether the awaited value was // fulfilled or rejected. MOZ_MUST_USE bool AsyncFunctionAwaitedFulfilled( - JSContext* cx, Handle<PromiseObject*> resultPromise, - Handle<AsyncFunctionGeneratorObject*> generator, HandleValue value); + JSContext* cx, Handle<AsyncFunctionGeneratorObject*> generator, + HandleValue value); MOZ_MUST_USE bool AsyncFunctionAwaitedRejected( - JSContext* cx, Handle<PromiseObject*> resultPromise, - Handle<AsyncFunctionGeneratorObject*> generator, HandleValue reason); + JSContext* cx, Handle<AsyncFunctionGeneratorObject*> generator, + HandleValue reason); + +class AsyncFunctionGeneratorObject : public AbstractGeneratorObject { + public: + enum { + PROMISE_SLOT = AbstractGeneratorObject::RESERVED_SLOTS, + + RESERVED_SLOTS + }; + + static const Class class_; + + static AsyncFunctionGeneratorObject* create(JSContext* cx, + HandleFunction asyncGen); + + PromiseObject* promise() { + return &getFixedSlot(PROMISE_SLOT).toObject().as<PromiseObject>(); + } +}; } // namespace js #endif /* vm_AsyncFunction_h */
--- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -2,16 +2,17 @@ * vim: set ts=8 sts=2 et sw=2 tw=80: * 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/GeneratorObject.h" #include "js/PropertySpec.h" +#include "vm/AsyncFunction.h" #include "vm/AsyncIteration.h" #include "vm/JSObject.h" #include "vm/ArrayObject-inl.h" #include "vm/Debugger-inl.h" #include "vm/JSAtom-inl.h" #include "vm/JSScript-inl.h" #include "vm/NativeObject-inl.h" @@ -28,18 +29,17 @@ JSObject* AbstractGeneratorObject::creat RootedFunction fun(cx, frame.callee()); Rooted<AbstractGeneratorObject*> genObj(cx); if (!fun->isAsync()) { genObj = GeneratorObject::create(cx, fun); } else if (fun->isGenerator()) { genObj = AsyncGeneratorObject::create(cx, fun); } else { - RootedObject proto(cx, nullptr); - genObj = NewObjectWithGivenProto<AsyncFunctionGeneratorObject>(cx, proto); + genObj = AsyncFunctionGeneratorObject::create(cx, fun); } if (!genObj) { return nullptr; } genObj->setCallee(*frame.callee()); genObj->setEnvironmentChain(*frame.environmentChain()); if (frame.script()->needsArgsObj()) { @@ -216,20 +216,16 @@ GeneratorObject* GeneratorObject::create const Class GeneratorObject::class_ = { "Generator", JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS)}; static const JSFunctionSpec generator_methods[] = { JS_SELF_HOSTED_FN("next", "GeneratorNext", 1, 0), JS_SELF_HOSTED_FN("throw", "GeneratorThrow", 1, 0), JS_SELF_HOSTED_FN("return", "GeneratorReturn", 1, 0), JS_FS_END}; -const Class AsyncFunctionGeneratorObject::class_ = { - "AsyncFunctionGenerator", - JSCLASS_HAS_RESERVED_SLOTS(AsyncFunctionGeneratorObject::RESERVED_SLOTS)}; - JSObject* js::NewSingletonObjectWithFunctionPrototype( JSContext* cx, Handle<GlobalObject*> global) { RootedObject proto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!proto) { return nullptr; } return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject);
--- a/js/src/vm/GeneratorObject.h +++ b/js/src/vm/GeneratorObject.h @@ -2,16 +2,17 @@ * vim: set ts=8 sts=2 et sw=2 tw=80: * 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/. */ #ifndef vm_GeneratorObject_h #define vm_GeneratorObject_h +#include "js/Class.h" #include "vm/ArgumentsObject.h" #include "vm/ArrayObject.h" #include "vm/JSContext.h" #include "vm/JSObject.h" #include "vm/Stack.h" namespace js { @@ -205,23 +206,16 @@ class GeneratorObject : public AbstractG public: enum { RESERVED_SLOTS = AbstractGeneratorObject::RESERVED_SLOTS }; static const Class class_; static GeneratorObject* create(JSContext* cx, HandleFunction fun); }; -class AsyncFunctionGeneratorObject : public AbstractGeneratorObject { - public: - enum { RESERVED_SLOTS = AbstractGeneratorObject::RESERVED_SLOTS }; - - static const Class class_; -}; - bool GeneratorThrowOrReturn(JSContext* cx, AbstractFramePtr frame, Handle<AbstractGeneratorObject*> obj, HandleValue val, uint32_t resumeKind); /** * Return the generator object associated with the given frame. The frame must * be a call frame for a generator. If the generator object hasn't been created * yet, or hasn't been stored in the stack slot yet, this returns null.
--- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -38,16 +38,17 @@ #include "js/CharacterEncoding.h" #include "js/CompilationAndEvaluation.h" #include "js/Date.h" #include "js/PropertySpec.h" #include "js/StableStringChars.h" #include "js/Wrapper.h" #include "util/StringBuffer.h" #include "vm/ArgumentsObject.h" +#include "vm/AsyncFunction.h" #include "vm/AsyncIteration.h" #include "vm/Compression.h" #include "vm/GeneratorObject.h" #include "vm/Interpreter.h" #include "vm/Iteration.h" #include "vm/JSContext.h" #include "vm/JSFunction.h" #include "vm/JSObject.h"