From 91ddb65d3b34c07c5026727de84dc91b5e0a43cd Mon Sep 17 00:00:00 2001 From: Maya Lekova Date: Mon, 14 May 2018 10:55:07 +0200 Subject: [PATCH] Revert promises optimizations due to regressions in async hooks Revert "[async-await] Eliminate throwaway promise in async functions." This reverts commit a840f1f8f7e6c9ab32dec456a954612619855093. Revert "[async-generators] Also avoid throwaway promise here." This reverts commit feb545ceba5cb477ba883b46b60142f441ad5a3d. Revert "[async-await] Turn await closures into intrinsics." This reverts commit d97bb317386506a6798386b74647cbe0502fce35. Revert "[async-generators] Add fast-path for primitives in AsyncGeneratorYield." This reverts commit e57b500eb26dc595609613963468910eb4bcae2e. Revert "[async-generators] Add fast-path to skip "then" lookup in AsyncGeneratorResolve." This reverts commit c15802e11e30976528d1b711a9b9e6ff6b490117. Revert "[promises] Correctly run before/after hooks for await." This reverts commit ca7639239fc13e992e857710cbf7dbaac87163bf. Bug: v8:7253, v8:7745 Change-Id: I25ad0d2df3cfbc84dbb431aa25b268bce8a39e89 Reviewed-on: https://chromium-review.googlesource.com/1049975 Commit-Queue: Maya Lekova Reviewed-by: Benedikt Meurer Cr-Commit-Position: refs/heads/master@{#53139} --- src/bootstrapper.cc | 72 ++++++ src/builtins/builtins-async-function-gen.cc | 94 +++++--- src/builtins/builtins-async-gen.cc | 207 ++++++++++++----- src/builtins/builtins-async-gen.h | 43 +++- src/builtins/builtins-async-generator-gen.cc | 213 ++++++++---------- src/builtins/builtins-definitions.h | 38 ++-- src/builtins/builtins-internal-gen.cc | 38 ++-- src/builtins/builtins-promise-gen.cc | 125 +++++----- src/builtins/builtins-promise-gen.h | 11 +- src/compiler/js-intrinsic-lowering.cc | 35 --- src/compiler/js-intrinsic-lowering.h | 4 - src/contexts.h | 83 ++++--- src/heap-symbols.h | 1 - src/interface-descriptors.h | 8 - src/interpreter/bytecode-generator.cc | 18 +- .../interpreter-intrinsics-generator.cc | 24 -- src/interpreter/interpreter-intrinsics.h | 4 - src/isolate.cc | 41 ++-- src/isolate.h | 5 +- src/lookup.cc | 7 - src/objects-debug.cc | 29 +-- src/objects-inl.h | 1 - src/objects-printer.cc | 6 +- src/objects.cc | 29 +-- src/objects/js-promise.h | 6 - src/objects/promise-inl.h | 6 +- src/objects/promise.h | 26 +-- src/runtime/runtime-generator.cc | 24 -- src/runtime/runtime-promise.cc | 30 ++- src/runtime/runtime.h | 4 - .../AsyncGenerators.golden | 12 +- .../bytecode_expectations/ForAwaitOf.golden | 18 +- .../bytecode_expectations/ForOfLoop.golden | 2 +- .../StandardForLoop.golden | 2 +- test/cctest/test-api.cc | 6 - tools/v8heapconst.py | 54 ++--- 36 files changed, 704 insertions(+), 622 deletions(-) diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 0eec2c6d09..8b272d0576 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1587,6 +1587,50 @@ void Genesis::InitializeGlobal(Handle global_object, native_context()->set_async_iterator_value_unwrap_shared_fun(*info); } + { // --- A s y n c G e n e r a t o r --- + Handle await_caught = + SimpleCreateFunction(isolate, factory->empty_string(), + Builtins::kAsyncGeneratorAwaitCaught, 1, false); + native_context()->set_async_generator_await_caught(*await_caught); + + Handle await_uncaught = + SimpleCreateFunction(isolate, factory->empty_string(), + Builtins::kAsyncGeneratorAwaitUncaught, 1, false); + native_context()->set_async_generator_await_uncaught(*await_uncaught); + + Handle info = SimpleCreateSharedFunctionInfo( + isolate, Builtins::kAsyncGeneratorAwaitResolveClosure, + factory->empty_string(), 1); + native_context()->set_async_generator_await_resolve_shared_fun(*info); + + info = SimpleCreateSharedFunctionInfo( + isolate, Builtins::kAsyncGeneratorAwaitRejectClosure, + factory->empty_string(), 1); + native_context()->set_async_generator_await_reject_shared_fun(*info); + + info = SimpleCreateSharedFunctionInfo( + isolate, Builtins::kAsyncGeneratorYieldResolveClosure, + factory->empty_string(), 1); + native_context()->set_async_generator_yield_resolve_shared_fun(*info); + + info = SimpleCreateSharedFunctionInfo( + isolate, Builtins::kAsyncGeneratorReturnResolveClosure, + factory->empty_string(), 1); + native_context()->set_async_generator_return_resolve_shared_fun(*info); + + info = SimpleCreateSharedFunctionInfo( + isolate, Builtins::kAsyncGeneratorReturnClosedResolveClosure, + factory->empty_string(), 1); + native_context()->set_async_generator_return_closed_resolve_shared_fun( + *info); + + info = SimpleCreateSharedFunctionInfo( + isolate, Builtins::kAsyncGeneratorReturnClosedRejectClosure, + factory->empty_string(), 1); + native_context()->set_async_generator_return_closed_reject_shared_fun( + *info); + } + { // --- A r r a y --- Handle array_function = InstallFunction( global, "Array", JS_ARRAY_TYPE, JSArray::kSize, 0, @@ -4025,6 +4069,34 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate, JSFunction::SetPrototype(async_function_constructor, async_function_prototype); + { + Handle function = + SimpleCreateFunction(isolate, factory->empty_string(), + Builtins::kAsyncFunctionAwaitCaught, 2, false); + native_context->set_async_function_await_caught(*function); + } + + { + Handle function = + SimpleCreateFunction(isolate, factory->empty_string(), + Builtins::kAsyncFunctionAwaitUncaught, 2, false); + native_context->set_async_function_await_uncaught(*function); + } + + { + Handle info = SimpleCreateSharedFunctionInfo( + isolate, Builtins::kAsyncFunctionAwaitRejectClosure, + factory->empty_string(), 1); + native_context->set_async_function_await_reject_shared_fun(*info); + } + + { + Handle info = SimpleCreateSharedFunctionInfo( + isolate, Builtins::kAsyncFunctionAwaitResolveClosure, + factory->empty_string(), 1); + native_context->set_async_function_await_resolve_shared_fun(*info); + } + { Handle function = SimpleCreateFunction(isolate, factory->empty_string(), diff --git a/src/builtins/builtins-async-function-gen.cc b/src/builtins/builtins-async-function-gen.cc index 0db53c687e..0d0e34ee0d 100644 --- a/src/builtins/builtins-async-function-gen.cc +++ b/src/builtins/builtins-async-function-gen.cc @@ -21,18 +21,37 @@ class AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler { Node* const awaited, Node* const outer_promise, const bool is_predicted_as_caught); - void AsyncFunctionAwaitResume(Node* const context, Node* const argument, - Node* const generator, - JSGeneratorObject::ResumeMode resume_mode); + void AsyncFunctionAwaitResumeClosure( + Node* const context, Node* const sent_value, + JSGeneratorObject::ResumeMode resume_mode); }; -void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResume( - Node* const context, Node* const argument, Node* const generator, +namespace { + +// Describe fields of Context associated with AsyncFunctionAwait resume +// closures. +// TODO(jgruber): Refactor to reuse code for upcoming async-generators. +class AwaitContext { + public: + enum Fields { kGeneratorSlot = Context::MIN_CONTEXT_SLOTS, kLength }; +}; + +} // anonymous namespace + +void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure( + Node* context, Node* sent_value, JSGeneratorObject::ResumeMode resume_mode) { - CSA_ASSERT(this, IsJSGeneratorObject(generator)); DCHECK(resume_mode == JSGeneratorObject::kNext || resume_mode == JSGeneratorObject::kThrow); + Node* const generator = + LoadContextElement(context, AwaitContext::kGeneratorSlot); + CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE)); + + // Inline version of GeneratorPrototypeNext / GeneratorPrototypeReturn with + // unnecessary runtime checks removed. + // TODO(jgruber): Refactor to reuse code from builtins-generator.cc. + // Ensure that the generator is neither closed nor running. CSA_SLOW_ASSERT( this, @@ -47,23 +66,31 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResume( // Resume the {receiver} using our trampoline. Callable callable = CodeFactory::ResumeGenerator(isolate()); - TailCallStub(callable, context, argument, generator); + CallStub(callable, context, sent_value, generator); + + // The resulting Promise is a throwaway, so it doesn't matter what it + // resolves to. What is important is that we don't end up keeping the + // whole chain of intermediate Promises alive by returning the return value + // of ResumeGenerator, as that would create a memory leak. } -TF_BUILTIN(AsyncFunctionAwaitFulfill, AsyncFunctionBuiltinsAssembler) { - Node* const argument = Parameter(Descriptor::kArgument); - Node* const generator = Parameter(Descriptor::kGenerator); +TF_BUILTIN(AsyncFunctionAwaitRejectClosure, AsyncFunctionBuiltinsAssembler) { + CSA_ASSERT_JS_ARGC_EQ(this, 1); + Node* const sentError = Parameter(Descriptor::kSentError); Node* const context = Parameter(Descriptor::kContext); - AsyncFunctionAwaitResume(context, argument, generator, - JSGeneratorObject::kNext); + + AsyncFunctionAwaitResumeClosure(context, sentError, + JSGeneratorObject::kThrow); + Return(UndefinedConstant()); } -TF_BUILTIN(AsyncFunctionAwaitReject, AsyncFunctionBuiltinsAssembler) { - Node* const argument = Parameter(Descriptor::kArgument); - Node* const generator = Parameter(Descriptor::kGenerator); +TF_BUILTIN(AsyncFunctionAwaitResolveClosure, AsyncFunctionBuiltinsAssembler) { + CSA_ASSERT_JS_ARGC_EQ(this, 1); + Node* const sentValue = Parameter(Descriptor::kSentValue); Node* const context = Parameter(Descriptor::kContext); - AsyncFunctionAwaitResume(context, argument, generator, - JSGeneratorObject::kThrow); + + AsyncFunctionAwaitResumeClosure(context, sentValue, JSGeneratorObject::kNext); + Return(UndefinedConstant()); } // ES#abstract-ops-async-function-await @@ -78,12 +105,25 @@ TF_BUILTIN(AsyncFunctionAwaitReject, AsyncFunctionBuiltinsAssembler) { void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait( Node* const context, Node* const generator, Node* const awaited, Node* const outer_promise, const bool is_predicted_as_caught) { - CSA_SLOW_ASSERT(this, IsJSGeneratorObject(generator)); - CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise)); + CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE)); + CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE)); - Await(context, generator, awaited, outer_promise, - Builtins::kAsyncFunctionAwaitFulfill, - Builtins::kAsyncFunctionAwaitReject, is_predicted_as_caught); + ContextInitializer init_closure_context = [&](Node* context) { + StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot, + generator); + }; + + // TODO(jgruber): AsyncBuiltinsAssembler::Await currently does not reuse + // the awaited promise if it is already a promise. Reuse is non-spec compliant + // but part of our old behavior gives us a couple of percent + // performance boost. + // TODO(jgruber): Use a faster specialized version of + // InternalPerformPromiseThen. + + Await(context, generator, awaited, outer_promise, AwaitContext::kLength, + init_closure_context, Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN, + Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN, + is_predicted_as_caught); // Return outer promise to avoid adding an load of the outer promise before // suspending in BytecodeGenerator. @@ -93,28 +133,30 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait( // Called by the parser from the desugaring of 'await' when catch // prediction indicates that there is a locally surrounding catch block. TF_BUILTIN(AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) { + CSA_ASSERT_JS_ARGC_EQ(this, 3); Node* const generator = Parameter(Descriptor::kGenerator); - Node* const value = Parameter(Descriptor::kValue); + Node* const awaited = Parameter(Descriptor::kAwaited); Node* const outer_promise = Parameter(Descriptor::kOuterPromise); Node* const context = Parameter(Descriptor::kContext); static const bool kIsPredictedAsCaught = true; - AsyncFunctionAwait(context, generator, value, outer_promise, + AsyncFunctionAwait(context, generator, awaited, outer_promise, kIsPredictedAsCaught); } // Called by the parser from the desugaring of 'await' when catch // prediction indicates no locally surrounding catch block. TF_BUILTIN(AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) { + CSA_ASSERT_JS_ARGC_EQ(this, 3); Node* const generator = Parameter(Descriptor::kGenerator); - Node* const value = Parameter(Descriptor::kValue); + Node* const awaited = Parameter(Descriptor::kAwaited); Node* const outer_promise = Parameter(Descriptor::kOuterPromise); Node* const context = Parameter(Descriptor::kContext); static const bool kIsPredictedAsCaught = false; - AsyncFunctionAwait(context, generator, value, outer_promise, + AsyncFunctionAwait(context, generator, awaited, outer_promise, kIsPredictedAsCaught); } diff --git a/src/builtins/builtins-async-gen.cc b/src/builtins/builtins-async-gen.cc index 073c96a2e0..ba0226d7b3 100644 --- a/src/builtins/builtins-async-gen.cc +++ b/src/builtins/builtins-async-gen.cc @@ -13,58 +13,6 @@ namespace internal { using compiler::Node; -void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value, - Node* outer_promise, - Builtins::Name fulfill_builtin, - Builtins::Name reject_builtin, - Node* is_predicted_as_caught) { - CSA_SLOW_ASSERT(this, Word32Or(IsJSAsyncGeneratorObject(generator), - IsJSGeneratorObject(generator))); - CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise)); - CSA_SLOW_ASSERT(this, IsBoolean(is_predicted_as_caught)); - - Node* const native_context = LoadNativeContext(context); - - // TODO(bmeurer): This could be optimized and folded into a single allocation. - Node* const promise = AllocateAndInitJSPromise(native_context); - Node* const promise_reactions = - LoadObjectField(promise, JSPromise::kReactionsOrResultOffset); - Node* const fulfill_handler = - HeapConstant(Builtins::CallableFor(isolate(), fulfill_builtin).code()); - Node* const reject_handler = - HeapConstant(Builtins::CallableFor(isolate(), reject_builtin).code()); - Node* const reaction = AllocatePromiseReaction( - promise_reactions, generator, fulfill_handler, reject_handler); - StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reaction); - PromiseSetHasHandler(promise); - - // Perform ! Call(promiseCapability.[[Resolve]], undefined, « value »). - CallBuiltin(Builtins::kResolvePromise, native_context, promise, value); - - // When debugging, we need to link from the {generator} to the - // {outer_promise} of the async function/generator. - Label done(this); - GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &done); - CallRuntime(Runtime::kSetProperty, native_context, generator, - LoadRoot(Heap::kgenerator_outer_promise_symbolRootIndex), - outer_promise, SmiConstant(LanguageMode::kStrict)); - GotoIf(IsFalse(is_predicted_as_caught), &done); - GotoIf(TaggedIsSmi(value), &done); - GotoIfNot(IsJSPromise(value), &done); - PromiseSetHandledHint(value); - Goto(&done); - BIND(&done); -} - -void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value, - Node* outer_promise, - Builtins::Name fulfill_builtin, - Builtins::Name reject_builtin, - bool is_predicted_as_caught) { - return Await(context, generator, value, outer_promise, fulfill_builtin, - reject_builtin, BooleanConstant(is_predicted_as_caught)); -} - namespace { // Describe fields of Context associated with the AsyncIterator unwrap closure. class ValueUnwrapContext { @@ -74,6 +22,161 @@ class ValueUnwrapContext { } // namespace +Node* AsyncBuiltinsAssembler::Await( + Node* context, Node* generator, Node* value, Node* outer_promise, + int context_length, const ContextInitializer& init_closure_context, + Node* on_resolve_context_index, Node* on_reject_context_index, + Node* is_predicted_as_caught) { + DCHECK_GE(context_length, Context::MIN_CONTEXT_SLOTS); + + Node* const native_context = LoadNativeContext(context); + + static const int kWrappedPromiseOffset = FixedArray::SizeFor(context_length); + static const int kThrowawayPromiseOffset = + kWrappedPromiseOffset + JSPromise::kSizeWithEmbedderFields; + static const int kResolveClosureOffset = + kThrowawayPromiseOffset + JSPromise::kSizeWithEmbedderFields; + static const int kRejectClosureOffset = + kResolveClosureOffset + JSFunction::kSizeWithoutPrototype; + static const int kTotalSize = + kRejectClosureOffset + JSFunction::kSizeWithoutPrototype; + + Node* const base = AllocateInNewSpace(kTotalSize); + Node* const closure_context = base; + { + // Initialize closure context + InitializeFunctionContext(native_context, closure_context, context_length); + init_closure_context(closure_context); + } + + // Let promiseCapability be ! NewPromiseCapability(%Promise%). + Node* const promise_fun = + LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); + CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun))); + Node* const promise_map = + LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); + // Assert that the JSPromise map has an instance size is + // JSPromise::kSizeWithEmbedderFields. + CSA_ASSERT(this, WordEqual(LoadMapInstanceSizeInWords(promise_map), + IntPtrConstant(JSPromise::kSizeWithEmbedderFields / + kPointerSize))); + Node* const wrapped_value = InnerAllocate(base, kWrappedPromiseOffset); + { + // Initialize Promise + StoreMapNoWriteBarrier(wrapped_value, promise_map); + InitializeJSObjectFromMap( + wrapped_value, promise_map, + IntPtrConstant(JSPromise::kSizeWithEmbedderFields)); + PromiseInit(wrapped_value); + } + + Node* const throwaway = InnerAllocate(base, kThrowawayPromiseOffset); + { + // Initialize throwawayPromise + StoreMapNoWriteBarrier(throwaway, promise_map); + InitializeJSObjectFromMap( + throwaway, promise_map, + IntPtrConstant(JSPromise::kSizeWithEmbedderFields)); + PromiseInit(throwaway); + } + + Node* const on_resolve = InnerAllocate(base, kResolveClosureOffset); + { + // Initialize resolve handler + InitializeNativeClosure(closure_context, native_context, on_resolve, + on_resolve_context_index); + } + + Node* const on_reject = InnerAllocate(base, kRejectClosureOffset); + { + // Initialize reject handler + InitializeNativeClosure(closure_context, native_context, on_reject, + on_reject_context_index); + } + + { + // Add PromiseHooks if needed + Label next(this); + GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &next); + CallRuntime(Runtime::kPromiseHookInit, context, wrapped_value, + outer_promise); + CallRuntime(Runtime::kPromiseHookInit, context, throwaway, wrapped_value); + Goto(&next); + BIND(&next); + } + + // Perform ! Call(promiseCapability.[[Resolve]], undefined, « promise »). + CallBuiltin(Builtins::kResolvePromise, context, wrapped_value, value); + + // The Promise will be thrown away and not handled, but it shouldn't trigger + // unhandled reject events as its work is done + PromiseSetHasHandler(throwaway); + + Label do_perform_promise_then(this); + GotoIfNot(IsDebugActive(), &do_perform_promise_then); + { + Label common(this); + GotoIf(TaggedIsSmi(value), &common); + GotoIfNot(HasInstanceType(value, JS_PROMISE_TYPE), &common); + { + // Mark the reject handler callback to be a forwarding edge, rather + // than a meaningful catch handler + Node* const key = + HeapConstant(factory()->promise_forwarding_handler_symbol()); + CallRuntime(Runtime::kSetProperty, context, on_reject, key, + TrueConstant(), SmiConstant(LanguageMode::kStrict)); + + GotoIf(IsFalse(is_predicted_as_caught), &common); + PromiseSetHandledHint(value); + } + + Goto(&common); + BIND(&common); + // Mark the dependency to outer Promise in case the throwaway Promise is + // found on the Promise stack + CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE)); + + Node* const key = HeapConstant(factory()->promise_handled_by_symbol()); + CallRuntime(Runtime::kSetProperty, context, throwaway, key, outer_promise, + SmiConstant(LanguageMode::kStrict)); + } + + Goto(&do_perform_promise_then); + BIND(&do_perform_promise_then); + return CallBuiltin(Builtins::kPerformPromiseThen, context, wrapped_value, + on_resolve, on_reject, throwaway); +} + +void AsyncBuiltinsAssembler::InitializeNativeClosure(Node* context, + Node* native_context, + Node* function, + Node* context_index) { + Node* const function_map = LoadContextElement( + native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); + // Ensure that we don't have to initialize prototype_or_initial_map field of + // JSFunction. + CSA_ASSERT(this, WordEqual(LoadMapInstanceSizeInWords(function_map), + IntPtrConstant(JSFunction::kSizeWithoutPrototype / + kPointerSize))); + STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize); + StoreMapNoWriteBarrier(function, function_map); + StoreObjectFieldRoot(function, JSObject::kPropertiesOrHashOffset, + Heap::kEmptyFixedArrayRootIndex); + StoreObjectFieldRoot(function, JSObject::kElementsOffset, + Heap::kEmptyFixedArrayRootIndex); + StoreObjectFieldRoot(function, JSFunction::kFeedbackCellOffset, + Heap::kManyClosuresCellRootIndex); + + Node* shared_info = LoadContextElement(native_context, context_index); + CSA_ASSERT(this, IsSharedFunctionInfo(shared_info)); + StoreObjectFieldNoWriteBarrier( + function, JSFunction::kSharedFunctionInfoOffset, shared_info); + StoreObjectFieldNoWriteBarrier(function, JSFunction::kContextOffset, context); + + Node* const code = GetSharedFunctionInfoCode(shared_info); + StoreObjectFieldNoWriteBarrier(function, JSFunction::kCodeOffset, code); +} + Node* AsyncBuiltinsAssembler::CreateUnwrapClosure(Node* native_context, Node* done) { Node* const map = LoadContextElement( diff --git a/src/builtins/builtins-async-gen.h b/src/builtins/builtins-async-gen.h index 70f68a498b..45d7c8689a 100644 --- a/src/builtins/builtins-async-gen.h +++ b/src/builtins/builtins-async-gen.h @@ -16,23 +16,48 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler { : PromiseBuiltinsAssembler(state) {} protected: - void Await(Node* context, Node* generator, Node* value, Node* outer_promise, - Builtins::Name fulfill_builtin, Builtins::Name reject_builtin, - Node* is_predicted_as_caught); - void Await(Node* context, Node* generator, Node* value, Node* outer_promise, - Builtins::Name fulfill_builtin, Builtins::Name reject_builtin, - bool is_predicted_as_caught); + typedef std::function ContextInitializer; + + // Perform steps to resume generator after `value` is resolved. + // `on_reject_context_index` is an index into the Native Context, which should + // point to a SharedFunctioninfo instance used to create the closure. The + // value following the reject index should be a similar value for the resolve + // closure. Returns the Promise-wrapped `value`. + Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise, + int context_length, + const ContextInitializer& init_closure_context, + Node* on_resolve_context_index, Node* on_reject_context_index, + Node* is_predicted_as_caught); + Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise, + int context_length, + const ContextInitializer& init_closure_context, + int on_resolve_context_index, int on_reject_context_index, + Node* is_predicted_as_caught) { + return Await(context, generator, value, outer_promise, context_length, + init_closure_context, IntPtrConstant(on_resolve_context_index), + IntPtrConstant(on_reject_context_index), + is_predicted_as_caught); + } + Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise, + int context_length, + const ContextInitializer& init_closure_context, + int on_resolve_context_index, int on_reject_context_index, + bool is_predicted_as_caught) { + return Await(context, generator, value, outer_promise, context_length, + init_closure_context, on_resolve_context_index, + on_reject_context_index, + BooleanConstant(is_predicted_as_caught)); + } // Return a new built-in function object as defined in // Async Iterator Value Unwrap Functions Node* CreateUnwrapClosure(Node* const native_context, Node* const done); private: + void InitializeNativeClosure(Node* context, Node* native_context, + Node* function, Node* context_index); Node* AllocateAsyncIteratorValueUnwrapContext(Node* native_context, Node* done); - Node* AllocateAwaitPromiseJobTask(Node* generator, Node* fulfill_handler, - Node* reject_handler, Node* promise, - Node* context); }; } // namespace internal diff --git a/src/builtins/builtins-async-generator-gen.cc b/src/builtins/builtins-async-generator-gen.cc index 290252da62..dd6c644196 100644 --- a/src/builtins/builtins-async-generator-gen.cc +++ b/src/builtins/builtins-async-generator-gen.cc @@ -140,8 +140,8 @@ class AsyncGeneratorBuiltinsAssembler : public AsyncBuiltinsAssembler { // for AsyncGenerators. template void AsyncGeneratorAwait(bool is_catchable); - void AsyncGeneratorAwaitResume( - Node* context, Node* generator, Node* argument, + void AsyncGeneratorAwaitResumeClosure( + Node* context, Node* value, JSAsyncGeneratorObject::ResumeMode resume_mode); }; @@ -219,9 +219,11 @@ Node* AsyncGeneratorBuiltinsAssembler::AllocateAsyncGeneratorRequest( return request; } -void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResume( - Node* context, Node* generator, Node* argument, +void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure( + Node* context, Node* value, JSAsyncGeneratorObject::ResumeMode resume_mode) { + Node* const generator = + LoadContextElement(context, AwaitContext::kGeneratorSlot); CSA_SLOW_ASSERT(this, TaggedIsAsyncGenerator(generator)); SetGeneratorNotAwaiting(generator); @@ -233,30 +235,36 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResume( JSGeneratorObject::kResumeModeOffset, SmiConstant(resume_mode)); - CallStub(CodeFactory::ResumeGenerator(isolate()), context, argument, - generator); + CallStub(CodeFactory::ResumeGenerator(isolate()), context, value, generator); TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator); } template void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwait(bool is_catchable) { - Node* const generator = Parameter(Descriptor::kGenerator); - Node* const value = Parameter(Descriptor::kValue); - Node* const context = Parameter(Descriptor::kContext); + Node* generator = Parameter(Descriptor::kGenerator); + Node* value = Parameter(Descriptor::kAwaited); + Node* context = Parameter(Descriptor::kContext); CSA_SLOW_ASSERT(this, TaggedIsAsyncGenerator(generator)); Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator); CSA_ASSERT(this, IsNotUndefined(request)); + ContextInitializer init_closure_context = [&](Node* context) { + StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot, + generator); + }; + Node* outer_promise = LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); + const int resolve_index = Context::ASYNC_GENERATOR_AWAIT_RESOLVE_SHARED_FUN; + const int reject_index = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN; + SetGeneratorAwaiting(generator); - Await(context, generator, value, outer_promise, - Builtins::kAsyncGeneratorAwaitFulfill, - Builtins::kAsyncGeneratorAwaitReject, is_catchable); + Await(context, generator, value, outer_promise, AwaitContext::kLength, + init_closure_context, resolve_index, reject_index, is_catchable); Return(UndefinedConstant()); } @@ -367,20 +375,18 @@ TF_BUILTIN(AsyncGeneratorPrototypeThrow, AsyncGeneratorBuiltinsAssembler) { "[AsyncGenerator].prototype.throw"); } -TF_BUILTIN(AsyncGeneratorAwaitFulfill, AsyncGeneratorBuiltinsAssembler) { - Node* const generator = Parameter(Descriptor::kGenerator); - Node* const argument = Parameter(Descriptor::kArgument); - Node* const context = Parameter(Descriptor::kContext); - AsyncGeneratorAwaitResume(context, generator, argument, - JSAsyncGeneratorObject::kNext); +TF_BUILTIN(AsyncGeneratorAwaitResolveClosure, AsyncGeneratorBuiltinsAssembler) { + Node* value = Parameter(Descriptor::kValue); + Node* context = Parameter(Descriptor::kContext); + AsyncGeneratorAwaitResumeClosure(context, value, + JSAsyncGeneratorObject::kNext); } -TF_BUILTIN(AsyncGeneratorAwaitReject, AsyncGeneratorBuiltinsAssembler) { - Node* const generator = Parameter(Descriptor::kGenerator); - Node* const argument = Parameter(Descriptor::kArgument); - Node* const context = Parameter(Descriptor::kContext); - AsyncGeneratorAwaitResume(context, generator, argument, - JSAsyncGeneratorObject::kThrow); +TF_BUILTIN(AsyncGeneratorAwaitRejectClosure, AsyncGeneratorBuiltinsAssembler) { + Node* value = Parameter(Descriptor::kValue); + Node* context = Parameter(Descriptor::kContext); + AsyncGeneratorAwaitResumeClosure(context, value, + JSAsyncGeneratorObject::kThrow); } TF_BUILTIN(AsyncGeneratorAwaitUncaught, AsyncGeneratorBuiltinsAssembler) { @@ -518,34 +524,11 @@ TF_BUILTIN(AsyncGeneratorResolve, AsyncGeneratorBuiltinsAssembler) { done); } - // We know that {iter_result} itself doesn't have any "then" property and - // we also know that the [[Prototype]] of {iter_result} is the intrinsic - // %ObjectPrototype%. So we can skip the [[Resolve]] logic here completely - // and directly call into the FulfillPromise operation if we can prove - // that the %ObjectPrototype% also doesn't have any "then" property. This - // is guarded by the Promise#then protector. - Label if_fast(this), if_slow(this, Label::kDeferred), return_promise(this); - GotoIfForceSlowPath(&if_slow); - Branch(IsPromiseThenProtectorCellInvalid(), &if_slow, &if_fast); - - BIND(&if_fast); - { - // Skip the "then" on {iter_result} and directly fulfill the {promise} - // with the {iter_result}. - CallBuiltin(Builtins::kFulfillPromise, context, promise, iter_result); - Goto(&return_promise); - } - - BIND(&if_slow); - { - // Perform Call(promiseCapability.[[Resolve]], undefined, «iteratorResult»). - CallBuiltin(Builtins::kResolvePromise, context, promise, iter_result); - Goto(&return_promise); - } + // Perform Call(promiseCapability.[[Resolve]], undefined, «iteratorResult»). + CallBuiltin(Builtins::kResolvePromise, context, promise, iter_result); // Per spec, AsyncGeneratorResolve() returns undefined. However, for the // benefit of %TraceExit(), return the Promise. - BIND(&return_promise); Return(promise); } @@ -571,54 +554,31 @@ TF_BUILTIN(AsyncGeneratorYield, AsyncGeneratorBuiltinsAssembler) { Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator); Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(request); - // Mark the generator as "awaiting". + ContextInitializer init_closure_context = [&](Node* context) { + StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot, + generator); + }; + + const int on_resolve = Context::ASYNC_GENERATOR_YIELD_RESOLVE_SHARED_FUN; + const int on_reject = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN; + SetGeneratorAwaiting(generator); - - // We can skip the creation of a temporary promise and the whole - // [[Resolve]] logic if we already know that the {value} that's - // being yielded is a primitive, as in that case we would immediately - // fulfill the temporary promise anyways and schedule a fulfill - // reaction job. This gives a nice performance boost for async - // generators that yield only primitives, e.g. numbers or strings. - Label if_primitive(this), if_generic(this); - GotoIfForceSlowPath(&if_generic); - GotoIf(IsPromiseHookEnabledOrDebugIsActive(), &if_generic); - GotoIf(TaggedIsSmi(value), &if_primitive); - Branch(IsJSReceiver(value), &if_generic, &if_primitive); - - BIND(&if_generic); - { - Await(context, generator, value, outer_promise, - Builtins::kAsyncGeneratorYieldFulfill, - Builtins::kAsyncGeneratorAwaitReject, is_caught); - Return(UndefinedConstant()); - } - - BIND(&if_primitive); - { - // For primitive {value}s we can skip the allocation of the temporary - // promise and the resolution of that, and directly allocate the fulfill - // reaction job. - Node* const microtask = AllocatePromiseReactionJobTask( - Heap::kPromiseFulfillReactionJobTaskMapRootIndex, context, value, - HeapConstant(Builtins::CallableFor( - isolate(), Builtins::kAsyncGeneratorYieldFulfill) - .code()), - generator); - TailCallBuiltin(Builtins::kEnqueueMicrotask, context, microtask); - } + Await(context, generator, value, outer_promise, AwaitContext::kLength, + init_closure_context, on_resolve, on_reject, is_caught); + Return(UndefinedConstant()); } -TF_BUILTIN(AsyncGeneratorYieldFulfill, AsyncGeneratorBuiltinsAssembler) { +TF_BUILTIN(AsyncGeneratorYieldResolveClosure, AsyncGeneratorBuiltinsAssembler) { Node* const context = Parameter(Descriptor::kContext); - Node* const generator = Parameter(Descriptor::kGenerator); - Node* const argument = Parameter(Descriptor::kArgument); + Node* const value = Parameter(Descriptor::kValue); + Node* const generator = + LoadContextElement(context, AwaitContext::kGeneratorSlot); SetGeneratorNotAwaiting(generator); // Per proposal-async-iteration/#sec-asyncgeneratoryield step 9 // Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *false*). - CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, argument, + CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, value, FalseConstant()); TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator); @@ -644,33 +604,39 @@ TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) { Node* const generator = Parameter(Descriptor::kGenerator); Node* const value = Parameter(Descriptor::kValue); Node* const is_caught = Parameter(Descriptor::kIsCaught); - Node* const context = Parameter(Descriptor::kContext); Node* const req = LoadFirstAsyncGeneratorRequestFromQueue(generator); - Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(req); CSA_ASSERT(this, IsNotUndefined(req)); - Label if_closed(this, Label::kDeferred), if_not_closed(this), done(this); + Label perform_await(this); + VARIABLE(var_on_resolve, MachineType::PointerRepresentation(), + IntPtrConstant( + Context::ASYNC_GENERATOR_RETURN_CLOSED_RESOLVE_SHARED_FUN)); + VARIABLE( + var_on_reject, MachineType::PointerRepresentation(), + IntPtrConstant(Context::ASYNC_GENERATOR_RETURN_CLOSED_REJECT_SHARED_FUN)); + Node* const state = LoadGeneratorState(generator); + GotoIf(IsGeneratorStateClosed(state), &perform_await); + var_on_resolve.Bind( + IntPtrConstant(Context::ASYNC_GENERATOR_RETURN_RESOLVE_SHARED_FUN)); + var_on_reject.Bind( + IntPtrConstant(Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN)); + Goto(&perform_await); + + BIND(&perform_await); + + ContextInitializer init_closure_context = [&](Node* context) { + StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot, + generator); + }; + SetGeneratorAwaiting(generator); - Branch(IsGeneratorStateClosed(state), &if_closed, &if_not_closed); + Node* const context = Parameter(Descriptor::kContext); + Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(req); + Await(context, generator, value, outer_promise, AwaitContext::kLength, + init_closure_context, var_on_resolve.value(), var_on_reject.value(), + is_caught); - BIND(&if_closed); - { - Await(context, generator, value, outer_promise, - Builtins::kAsyncGeneratorReturnClosedFulfill, - Builtins::kAsyncGeneratorReturnClosedReject, is_caught); - Goto(&done); - } - - BIND(&if_not_closed); - { - Await(context, generator, value, outer_promise, - Builtins::kAsyncGeneratorReturnFulfill, - Builtins::kAsyncGeneratorAwaitReject, is_caught); - Goto(&done); - } - - BIND(&done); Return(UndefinedConstant()); } @@ -678,44 +644,47 @@ TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) { // Resume the generator with "return" resume_mode, and finally perform // AsyncGeneratorResumeNext. Per // proposal-async-iteration/#sec-asyncgeneratoryield step 8.e -TF_BUILTIN(AsyncGeneratorReturnFulfill, AsyncGeneratorBuiltinsAssembler) { - Node* const generator = Parameter(Descriptor::kGenerator); - Node* const argument = Parameter(Descriptor::kArgument); +TF_BUILTIN(AsyncGeneratorReturnResolveClosure, + AsyncGeneratorBuiltinsAssembler) { Node* const context = Parameter(Descriptor::kContext); - AsyncGeneratorAwaitResume(context, generator, argument, - JSGeneratorObject::kReturn); + Node* const value = Parameter(Descriptor::kValue); + AsyncGeneratorAwaitResumeClosure(context, value, JSGeneratorObject::kReturn); } // On-resolve closure for Await in AsyncGeneratorReturn // Perform AsyncGeneratorResolve({awaited_value}, true) and finally perform // AsyncGeneratorResumeNext. -TF_BUILTIN(AsyncGeneratorReturnClosedFulfill, AsyncGeneratorBuiltinsAssembler) { - Node* const generator = Parameter(Descriptor::kGenerator); - Node* const argument = Parameter(Descriptor::kArgument); +TF_BUILTIN(AsyncGeneratorReturnClosedResolveClosure, + AsyncGeneratorBuiltinsAssembler) { Node* const context = Parameter(Descriptor::kContext); + Node* const value = Parameter(Descriptor::kValue); + Node* const generator = + LoadContextElement(context, AwaitContext::kGeneratorSlot); SetGeneratorNotAwaiting(generator); // https://tc39.github.io/proposal-async-iteration/ // #async-generator-resume-next-return-processor-fulfilled step 2: // Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *true*). - CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, argument, + CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, value, TrueConstant()); TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator); } -TF_BUILTIN(AsyncGeneratorReturnClosedReject, AsyncGeneratorBuiltinsAssembler) { - Node* const generator = Parameter(Descriptor::kGenerator); - Node* const argument = Parameter(Descriptor::kArgument); +TF_BUILTIN(AsyncGeneratorReturnClosedRejectClosure, + AsyncGeneratorBuiltinsAssembler) { Node* const context = Parameter(Descriptor::kContext); + Node* const value = Parameter(Descriptor::kValue); + Node* const generator = + LoadContextElement(context, AwaitContext::kGeneratorSlot); SetGeneratorNotAwaiting(generator); // https://tc39.github.io/proposal-async-iteration/ // #async-generator-resume-next-return-processor-rejected step 2: // Return ! AsyncGeneratorReject(_F_.[[Generator]], _reason_). - CallBuiltin(Builtins::kAsyncGeneratorReject, context, generator, argument); + CallBuiltin(Builtins::kAsyncGeneratorReject, context, generator, value); TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator); } diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h index d0ef062903..7daaa69f8d 100644 --- a/src/builtins/builtins-definitions.h +++ b/src/builtins/builtins-definitions.h @@ -375,10 +375,10 @@ namespace internal { CPP(ArrayBufferPrototypeSlice) \ \ /* AsyncFunction */ \ - TFC(AsyncFunctionAwaitFulfill, PromiseReactionHandler, 1) \ - TFC(AsyncFunctionAwaitReject, PromiseReactionHandler, 1) \ - TFS(AsyncFunctionAwaitCaught, kGenerator, kValue, kOuterPromise) \ - TFS(AsyncFunctionAwaitUncaught, kGenerator, kValue, kOuterPromise) \ + TFJ(AsyncFunctionAwaitCaught, 3, kGenerator, kAwaited, kOuterPromise) \ + TFJ(AsyncFunctionAwaitUncaught, 3, kGenerator, kAwaited, kOuterPromise) \ + TFJ(AsyncFunctionAwaitRejectClosure, 1, kSentError) \ + TFJ(AsyncFunctionAwaitResolveClosure, 1, kSentValue) \ TFJ(AsyncFunctionPromiseCreate, 0) \ TFJ(AsyncFunctionPromiseRelease, 1, kPromise) \ \ @@ -835,8 +835,8 @@ namespace internal { /* ES #sec-promise.prototype.catch */ \ TFJ(PromisePrototypeCatch, 1, kOnRejected) \ /* ES #sec-promisereactionjob */ \ - TFS(PromiseRejectReactionJob, kReason, kHandler, kPayload) \ - TFS(PromiseFulfillReactionJob, kValue, kHandler, kPayload) \ + TFS(PromiseRejectReactionJob, kReason, kHandler, kPromiseOrCapability) \ + TFS(PromiseFulfillReactionJob, kValue, kHandler, kPromiseOrCapability) \ /* ES #sec-promiseresolvethenablejob */ \ TFS(PromiseResolveThenableJob, kPromiseToResolve, kThenable, kThen) \ /* ES #sec-promise.resolve */ \ @@ -1203,17 +1203,6 @@ namespace internal { \ /* AsyncGenerator */ \ \ - /* Await (proposal-async-iteration/#await), with resume behaviour */ \ - /* specific to Async Generators. Internal / Not exposed to JS code. */ \ - TFS(AsyncGeneratorAwaitCaught, kGenerator, kValue) \ - TFS(AsyncGeneratorAwaitUncaught, kGenerator, kValue) \ - TFC(AsyncGeneratorAwaitFulfill, PromiseReactionHandler, 1) \ - TFC(AsyncGeneratorAwaitReject, PromiseReactionHandler, 1) \ - TFC(AsyncGeneratorYieldFulfill, PromiseReactionHandler, 1) \ - TFC(AsyncGeneratorReturnClosedFulfill, PromiseReactionHandler, 1) \ - TFC(AsyncGeneratorReturnClosedReject, PromiseReactionHandler, 1) \ - TFC(AsyncGeneratorReturnFulfill, PromiseReactionHandler, 1) \ - \ TFS(AsyncGeneratorResolve, kGenerator, kValue, kDone) \ TFS(AsyncGeneratorReject, kGenerator, kValue) \ TFS(AsyncGeneratorYield, kGenerator, kValue, kIsCaught) \ @@ -1236,6 +1225,17 @@ namespace internal { TFJ(AsyncGeneratorPrototypeThrow, \ SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ \ + /* Await (proposal-async-iteration/#await), with resume behaviour */ \ + /* specific to Async Generators. Internal / Not exposed to JS code. */ \ + TFJ(AsyncGeneratorAwaitCaught, 2, kGenerator, kAwaited) \ + TFJ(AsyncGeneratorAwaitUncaught, 2, kGenerator, kAwaited) \ + TFJ(AsyncGeneratorAwaitResolveClosure, 1, kValue) \ + TFJ(AsyncGeneratorAwaitRejectClosure, 1, kValue) \ + TFJ(AsyncGeneratorYieldResolveClosure, 1, kValue) \ + TFJ(AsyncGeneratorReturnClosedResolveClosure, 1, kValue) \ + TFJ(AsyncGeneratorReturnClosedRejectClosure, 1, kValue) \ + TFJ(AsyncGeneratorReturnResolveClosure, 1, kValue) \ + \ /* Async-from-Sync Iterator */ \ \ /* %AsyncFromSyncIteratorPrototype% */ \ @@ -1311,7 +1311,11 @@ namespace internal { V(AsyncFromSyncIteratorPrototypeNext) \ V(AsyncFromSyncIteratorPrototypeReturn) \ V(AsyncFromSyncIteratorPrototypeThrow) \ + V(AsyncFunctionAwaitCaught) \ + V(AsyncFunctionAwaitUncaught) \ V(AsyncGeneratorResolve) \ + V(AsyncGeneratorAwaitCaught) \ + V(AsyncGeneratorAwaitUncaught) \ V(PromiseAll) \ V(PromiseConstructor) \ V(PromiseConstructorLazyDeoptContinuation) \ diff --git a/src/builtins/builtins-internal-gen.cc b/src/builtins/builtins-internal-gen.cc index 5c3842761e..c1bf7df2ec 100644 --- a/src/builtins/builtins-internal-gen.cc +++ b/src/builtins/builtins-internal-gen.cc @@ -669,7 +669,7 @@ class InternalBuiltinsAssembler : public CodeStubAssembler { void LeaveMicrotaskContext(); void RunPromiseHook(Runtime::FunctionId id, TNode context, - SloppyTNode payload); + SloppyTNode promise_or_capability); TNode GetPendingException() { auto ref = ExternalReference::Create(kPendingExceptionAddress, isolate()); @@ -790,12 +790,20 @@ void InternalBuiltinsAssembler::LeaveMicrotaskContext() { void InternalBuiltinsAssembler::RunPromiseHook( Runtime::FunctionId id, TNode context, - SloppyTNode payload) { + SloppyTNode promise_or_capability) { Label hook(this, Label::kDeferred), done_hook(this); Branch(IsPromiseHookEnabledOrDebugIsActive(), &hook, &done_hook); BIND(&hook); { - CallRuntime(id, context, payload); + // Get to the underlying JSPromise instance. + Node* const promise = Select( + IsJSPromise(promise_or_capability), + [=] { return promise_or_capability; }, + [=] { + return CAST(LoadObjectField(promise_or_capability, + PromiseCapability::kPromiseOffset)); + }); + CallRuntime(id, context, promise); Goto(&done_hook); } BIND(&done_hook); @@ -1008,19 +1016,21 @@ TF_BUILTIN(RunMicrotasks, InternalBuiltinsAssembler) { LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset); Node* const handler = LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset); - Node* const payload = - LoadObjectField(microtask, PromiseReactionJobTask::kPayloadOffset); + Node* const promise_or_capability = LoadObjectField( + microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset); // Run the promise before/debug hook if enabled. - RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context, payload); + RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context, + promise_or_capability); Node* const result = CallBuiltin(Builtins::kPromiseFulfillReactionJob, microtask_context, - argument, handler, payload); + argument, handler, promise_or_capability); GotoIfException(result, &if_exception, &var_exception); // Run the promise after/debug hook if enabled. - RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context, payload); + RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context, + promise_or_capability); LeaveMicrotaskContext(); SetCurrentContext(current_context); @@ -1041,19 +1051,21 @@ TF_BUILTIN(RunMicrotasks, InternalBuiltinsAssembler) { LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset); Node* const handler = LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset); - Node* const payload = - LoadObjectField(microtask, PromiseReactionJobTask::kPayloadOffset); + Node* const promise_or_capability = LoadObjectField( + microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset); // Run the promise before/debug hook if enabled. - RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context, payload); + RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context, + promise_or_capability); Node* const result = CallBuiltin(Builtins::kPromiseRejectReactionJob, microtask_context, - argument, handler, payload); + argument, handler, promise_or_capability); GotoIfException(result, &if_exception, &var_exception); // Run the promise after/debug hook if enabled. - RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context, payload); + RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context, + promise_or_capability); LeaveMicrotaskContext(); SetCurrentContext(current_context); diff --git a/src/builtins/builtins-promise-gen.cc b/src/builtins/builtins-promise-gen.cc index dd38dbc543..868b45a831 100644 --- a/src/builtins/builtins-promise-gen.cc +++ b/src/builtins/builtins-promise-gen.cc @@ -391,15 +391,15 @@ TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { Return(result_promise); } -Node* PromiseBuiltinsAssembler::AllocatePromiseReaction(Node* next, - Node* payload, - Node* fulfill_handler, - Node* reject_handler) { +Node* PromiseBuiltinsAssembler::AllocatePromiseReaction( + Node* next, Node* promise_or_capability, Node* fulfill_handler, + Node* reject_handler) { Node* const reaction = Allocate(PromiseReaction::kSize); StoreMapNoWriteBarrier(reaction, Heap::kPromiseReactionMapRootIndex); StoreObjectFieldNoWriteBarrier(reaction, PromiseReaction::kNextOffset, next); - StoreObjectFieldNoWriteBarrier(reaction, PromiseReaction::kPayloadOffset, - payload); + StoreObjectFieldNoWriteBarrier(reaction, + PromiseReaction::kPromiseOrCapabilityOffset, + promise_or_capability); StoreObjectFieldNoWriteBarrier( reaction, PromiseReaction::kFulfillHandlerOffset, fulfill_handler); StoreObjectFieldNoWriteBarrier( @@ -408,7 +408,8 @@ Node* PromiseBuiltinsAssembler::AllocatePromiseReaction(Node* next, } Node* PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask( - Node* map, Node* context, Node* argument, Node* handler, Node* payload) { + Node* map, Node* context, Node* argument, Node* handler, + Node* promise_or_capability) { Node* const microtask = Allocate(PromiseReactionJobTask::kSize); StoreMapNoWriteBarrier(microtask, map); StoreObjectFieldNoWriteBarrier( @@ -418,18 +419,19 @@ Node* PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask( StoreObjectFieldNoWriteBarrier( microtask, PromiseReactionJobTask::kHandlerOffset, handler); StoreObjectFieldNoWriteBarrier( - microtask, PromiseReactionJobTask::kPayloadOffset, payload); + microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset, + promise_or_capability); return microtask; } Node* PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask( Heap::RootListIndex map_root_index, Node* context, Node* argument, - Node* handler, Node* payload) { + Node* handler, Node* promise_or_capability) { DCHECK(map_root_index == Heap::kPromiseFulfillReactionJobTaskMapRootIndex || map_root_index == Heap::kPromiseRejectReactionJobTaskMapRootIndex); Node* const map = LoadRoot(map_root_index); return AllocatePromiseReactionJobTask(map, context, argument, handler, - payload); + promise_or_capability); } Node* PromiseBuiltinsAssembler::AllocatePromiseResolveThenableJobTask( @@ -502,8 +504,8 @@ Node* PromiseBuiltinsAssembler::TriggerPromiseReactions( context); STATIC_ASSERT(PromiseReaction::kFulfillHandlerOffset == PromiseReactionJobTask::kHandlerOffset); - STATIC_ASSERT(PromiseReaction::kPayloadOffset == - PromiseReactionJobTask::kPayloadOffset); + STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset == + PromiseReactionJobTask::kPromiseOrCapabilityOffset); } else { Node* handler = LoadObjectField(current, PromiseReaction::kRejectHandlerOffset); @@ -515,8 +517,8 @@ Node* PromiseBuiltinsAssembler::TriggerPromiseReactions( context); StoreObjectField(current, PromiseReactionJobTask::kHandlerOffset, handler); - STATIC_ASSERT(PromiseReaction::kPayloadOffset == - PromiseReactionJobTask::kPayloadOffset); + STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset == + PromiseReactionJobTask::kPromiseOrCapabilityOffset); } CallBuiltin(Builtins::kEnqueueMicrotask, NoContextConstant(), current); Goto(&loop); @@ -1118,28 +1120,20 @@ TF_BUILTIN(PromiseResolveThenableJob, PromiseBuiltinsAssembler) { // ES #sec-promisereactionjob void PromiseBuiltinsAssembler::PromiseReactionJob(Node* context, Node* argument, - Node* handler, Node* payload, + Node* handler, + Node* promise_or_capability, PromiseReaction::Type type) { CSA_ASSERT(this, TaggedIsNotSmi(handler)); - CSA_ASSERT(this, Word32Or(IsCallable(handler), - Word32Or(IsCode(handler), IsUndefined(handler)))); - CSA_ASSERT(this, TaggedIsNotSmi(payload)); + CSA_ASSERT(this, Word32Or(IsUndefined(handler), IsCallable(handler))); + CSA_ASSERT(this, TaggedIsNotSmi(promise_or_capability)); + CSA_ASSERT(this, Word32Or(IsJSPromise(promise_or_capability), + IsPromiseCapability(promise_or_capability))); VARIABLE(var_handler_result, MachineRepresentation::kTagged, argument); - Label if_handler_callable(this), if_fulfill(this), if_reject(this), - if_code_handler(this); - - GotoIf(IsUndefined(handler), - type == PromiseReaction::kFulfill ? &if_fulfill : &if_reject); - Branch(IsCode(handler), &if_code_handler, &if_handler_callable); - - BIND(&if_code_handler); - { - // The {handler} is a Code object that knows how to deal with - // the {payload} and the {argument}. - PromiseReactionHandlerDescriptor descriptor(isolate()); - TailCallStub(descriptor, handler, context, argument, payload); - } + Label if_handler_callable(this), if_fulfill(this), if_reject(this); + Branch(IsUndefined(handler), + type == PromiseReaction::kFulfill ? &if_fulfill : &if_reject, + &if_handler_callable); BIND(&if_handler_callable); { @@ -1155,22 +1149,24 @@ void PromiseBuiltinsAssembler::PromiseReactionJob(Node* context, Node* argument, { Label if_promise(this), if_promise_capability(this, Label::kDeferred); Node* const value = var_handler_result.value(); - Branch(IsPromiseCapability(payload), &if_promise_capability, &if_promise); + Branch(IsPromiseCapability(promise_or_capability), &if_promise_capability, + &if_promise); BIND(&if_promise); { // For fast native promises we can skip the indirection // via the promiseCapability.[[Resolve]] function and // run the resolve logic directly from here. - TailCallBuiltin(Builtins::kResolvePromise, context, payload, value); + TailCallBuiltin(Builtins::kResolvePromise, context, promise_or_capability, + value); } BIND(&if_promise_capability); { // In the general case we need to call the (user provided) // promiseCapability.[[Resolve]] function. - Node* const resolve = - LoadObjectField(payload, PromiseCapability::kResolveOffset); + Node* const resolve = LoadObjectField(promise_or_capability, + PromiseCapability::kResolveOffset); Node* const result = CallJS( CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined), context, resolve, UndefinedConstant(), value); @@ -1183,15 +1179,16 @@ void PromiseBuiltinsAssembler::PromiseReactionJob(Node* context, Node* argument, if (type == PromiseReaction::kReject) { Label if_promise(this), if_promise_capability(this, Label::kDeferred); Node* const reason = var_handler_result.value(); - Branch(IsPromiseCapability(payload), &if_promise_capability, &if_promise); + Branch(IsPromiseCapability(promise_or_capability), &if_promise_capability, + &if_promise); BIND(&if_promise); { // For fast native promises we can skip the indirection // via the promiseCapability.[[Reject]] function and // run the resolve logic directly from here. - TailCallBuiltin(Builtins::kRejectPromise, context, payload, reason, - FalseConstant()); + TailCallBuiltin(Builtins::kRejectPromise, context, promise_or_capability, + reason, FalseConstant()); } BIND(&if_promise_capability); @@ -1201,8 +1198,8 @@ void PromiseBuiltinsAssembler::PromiseReactionJob(Node* context, Node* argument, Label if_exception(this, Label::kDeferred); VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant()); - Node* const reject = - LoadObjectField(payload, PromiseCapability::kRejectOffset); + Node* const reject = LoadObjectField(promise_or_capability, + PromiseCapability::kRejectOffset); Node* const result = CallJS( CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined), context, reject, UndefinedConstant(), reason); @@ -1219,7 +1216,8 @@ void PromiseBuiltinsAssembler::PromiseReactionJob(Node* context, Node* argument, // predictions in the debugger will be wrong, which just walks the stack // and checks for certain builtins. TailCallBuiltin(Builtins::kPromiseRejectReactionJob, context, - var_handler_result.value(), UndefinedConstant(), payload); + var_handler_result.value(), UndefinedConstant(), + promise_or_capability); } } @@ -1228,9 +1226,10 @@ TF_BUILTIN(PromiseFulfillReactionJob, PromiseBuiltinsAssembler) { Node* const context = Parameter(Descriptor::kContext); Node* const value = Parameter(Descriptor::kValue); Node* const handler = Parameter(Descriptor::kHandler); - Node* const payload = Parameter(Descriptor::kPayload); + Node* const promise_or_capability = + Parameter(Descriptor::kPromiseOrCapability); - PromiseReactionJob(context, value, handler, payload, + PromiseReactionJob(context, value, handler, promise_or_capability, PromiseReaction::kFulfill); } @@ -1239,9 +1238,10 @@ TF_BUILTIN(PromiseRejectReactionJob, PromiseBuiltinsAssembler) { Node* const context = Parameter(Descriptor::kContext); Node* const reason = Parameter(Descriptor::kReason); Node* const handler = Parameter(Descriptor::kHandler); - Node* const payload = Parameter(Descriptor::kPayload); + Node* const promise_or_capability = + Parameter(Descriptor::kPromiseOrCapability); - PromiseReactionJob(context, reason, handler, payload, + PromiseReactionJob(context, reason, handler, promise_or_capability, PromiseReaction::kReject); } @@ -1717,23 +1717,21 @@ TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) { // 7. If Type(resolution) is not Object, then GotoIf(TaggedIsSmi(resolution), &if_fulfill); - Node* const resolution_map = LoadMap(resolution); - GotoIfNot(IsJSReceiverMap(resolution_map), &if_fulfill); + Node* const result_map = LoadMap(resolution); + GotoIfNot(IsJSReceiverMap(result_map), &if_fulfill); // We can skip the "then" lookup on {resolution} if its [[Prototype]] // is the (initial) Promise.prototype and the Promise#then protector // is intact, as that guards the lookup path for the "then" property // on JSPromise instances which have the (initial) %PromisePrototype%. - Label if_fast(this), if_generic(this), if_slow(this, Label::kDeferred); + Label if_fast(this), if_slow(this, Label::kDeferred); Node* const native_context = LoadNativeContext(context); - GotoIfForceSlowPath(&if_slow); - GotoIf(IsPromiseThenProtectorCellInvalid(), &if_slow); - GotoIfNot(IsJSPromiseMap(resolution_map), &if_generic); - Node* const promise_prototype = - LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX); - Branch(WordEqual(LoadMapPrototype(resolution_map), promise_prototype), - &if_fast, &if_slow); + BranchIfPromiseThenLookupChainIntact(native_context, result_map, &if_fast, + &if_slow); + // Resolution is a native promise and if it's already resolved or + // rejected, shortcircuit the resolution procedure by directly + // reusing the value from the promise. BIND(&if_fast); { Node* const then = @@ -1742,21 +1740,6 @@ TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) { Goto(&do_enqueue); } - BIND(&if_generic); - { - // We can skip the lookup of "then" if the {resolution} is a (newly - // created) IterResultObject, as the Promise#then protector also - // ensures that the intrinsic %ObjectPrototype% doesn't contain any - // "then" property. This helps to avoid negative lookups on iterator - // results from async generators. - CSA_ASSERT(this, IsJSReceiverMap(resolution_map)); - CSA_ASSERT(this, Word32BinaryNot(IsPromiseThenProtectorCellInvalid())); - Node* const iterator_result_map = - LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX); - Branch(WordEqual(resolution_map, iterator_result_map), &if_fulfill, - &if_slow); - } - BIND(&if_slow); { // 8. Let then be Get(resolution, "then"). diff --git a/src/builtins/builtins-promise-gen.h b/src/builtins/builtins-promise-gen.h index f21d86a141..694cea28c0 100644 --- a/src/builtins/builtins-promise-gen.h +++ b/src/builtins/builtins-promise-gen.h @@ -85,14 +85,16 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler { Node* AllocateAndSetJSPromise(Node* context, v8::Promise::PromiseState status, Node* result); - Node* AllocatePromiseReaction(Node* next, Node* payload, + Node* AllocatePromiseReaction(Node* next, Node* promise_or_capability, Node* fulfill_handler, Node* reject_handler); Node* AllocatePromiseReactionJobTask(Heap::RootListIndex map_root_index, Node* context, Node* argument, - Node* handler, Node* payload); + Node* handler, + Node* promise_or_capability); Node* AllocatePromiseReactionJobTask(Node* map, Node* context, Node* argument, - Node* handler, Node* payload); + Node* handler, + Node* promise_or_capability); Node* AllocatePromiseResolveThenableJobTask(Node* promise_to_resolve, Node* then, Node* thenable, Node* context); @@ -192,7 +194,8 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler { Node* PromiseStatus(Node* promise); void PromiseReactionJob(Node* context, Node* argument, Node* handler, - Node* payload, PromiseReaction::Type type); + Node* promise_or_capability, + PromiseReaction::Type type); Node* IsPromiseStatus(Node* actual, v8::Promise::PromiseState expected); void PromiseSetStatus(Node* promise, v8::Promise::PromiseState status); diff --git a/src/compiler/js-intrinsic-lowering.cc b/src/compiler/js-intrinsic-lowering.cc index c570a1f8dd..d9742e47d9 100644 --- a/src/compiler/js-intrinsic-lowering.cc +++ b/src/compiler/js-intrinsic-lowering.cc @@ -41,14 +41,6 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) { return ReduceCreateJSGeneratorObject(node); case Runtime::kInlineGeneratorGetInputOrDebugPos: return ReduceGeneratorGetInputOrDebugPos(node); - case Runtime::kInlineAsyncFunctionAwaitCaught: - return ReduceAsyncFunctionAwaitCaught(node); - case Runtime::kInlineAsyncFunctionAwaitUncaught: - return ReduceAsyncFunctionAwaitUncaught(node); - case Runtime::kInlineAsyncGeneratorAwaitCaught: - return ReduceAsyncGeneratorAwaitCaught(node); - case Runtime::kInlineAsyncGeneratorAwaitUncaught: - return ReduceAsyncGeneratorAwaitUncaught(node); case Runtime::kInlineAsyncGeneratorReject: return ReduceAsyncGeneratorReject(node); case Runtime::kInlineAsyncGeneratorResolve: @@ -185,33 +177,6 @@ Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) { return Change(node, op, generator, effect, control); } -Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitCaught(Node* node) { - return Change( - node, - Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitCaught), 0); -} - -Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitUncaught(Node* node) { - return Change( - node, - Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitUncaught), - 0); -} - -Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitCaught(Node* node) { - return Change( - node, - Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorAwaitCaught), - 0); -} - -Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitUncaught(Node* node) { - return Change( - node, - Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorAwaitUncaught), - 0); -} - Reduction JSIntrinsicLowering::ReduceAsyncGeneratorReject(Node* node) { return Change( node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorReject), diff --git a/src/compiler/js-intrinsic-lowering.h b/src/compiler/js-intrinsic-lowering.h index fb745986a6..18fe1248c7 100644 --- a/src/compiler/js-intrinsic-lowering.h +++ b/src/compiler/js-intrinsic-lowering.h @@ -45,10 +45,6 @@ class V8_EXPORT_PRIVATE JSIntrinsicLowering final Reduction ReduceCreateJSGeneratorObject(Node* node); Reduction ReduceGeneratorClose(Node* node); Reduction ReduceGeneratorGetInputOrDebugPos(Node* node); - Reduction ReduceAsyncFunctionAwaitCaught(Node* node); - Reduction ReduceAsyncFunctionAwaitUncaught(Node* node); - Reduction ReduceAsyncGeneratorAwaitCaught(Node* node); - Reduction ReduceAsyncGeneratorAwaitUncaught(Node* node); Reduction ReduceAsyncGeneratorReject(Node* node); Reduction ReduceAsyncGeneratorResolve(Node* node); Reduction ReduceAsyncGeneratorYield(Node* node); diff --git a/src/contexts.h b/src/contexts.h index 4cfbb29f06..763f30f193 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -32,35 +32,44 @@ enum ContextLookupFlags { // must always be allocated via Heap::AllocateContext() or // Factory::NewContext. -#define NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(V) \ - V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \ - async_function_promise_create) \ - V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \ - async_function_promise_release) \ - V(IS_ARRAYLIKE, JSFunction, is_arraylike) \ - V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \ - V(MAKE_ERROR_INDEX, JSFunction, make_error) \ - V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \ - V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \ - V(MAKE_TYPE_ERROR_INDEX, JSFunction, make_type_error) \ - V(MAKE_URI_ERROR_INDEX, JSFunction, make_uri_error) \ - V(OBJECT_CREATE, JSFunction, object_create) \ - V(OBJECT_DEFINE_PROPERTIES, JSFunction, object_define_properties) \ - V(OBJECT_DEFINE_PROPERTY, JSFunction, object_define_property) \ - V(OBJECT_GET_PROTOTYPE_OF, JSFunction, object_get_prototype_of) \ - V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \ - V(OBJECT_KEYS, JSFunction, object_keys) \ - V(REGEXP_INTERNAL_MATCH, JSFunction, regexp_internal_match) \ - V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \ - V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \ - V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \ - V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \ - V(MATH_FLOOR_INDEX, JSFunction, math_floor) \ - V(MATH_POW_INDEX, JSFunction, math_pow) \ - V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \ - promise_internal_constructor) \ - V(IS_PROMISE_INDEX, JSFunction, is_promise) \ - V(PROMISE_THEN_INDEX, JSFunction, promise_then) +#define NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(V) \ + V(ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX, JSFunction, \ + async_function_await_caught) \ + V(ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX, JSFunction, \ + async_function_await_uncaught) \ + V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \ + async_function_promise_create) \ + V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \ + async_function_promise_release) \ + V(IS_ARRAYLIKE, JSFunction, is_arraylike) \ + V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \ + V(MAKE_ERROR_INDEX, JSFunction, make_error) \ + V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \ + V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \ + V(MAKE_TYPE_ERROR_INDEX, JSFunction, make_type_error) \ + V(MAKE_URI_ERROR_INDEX, JSFunction, make_uri_error) \ + V(OBJECT_CREATE, JSFunction, object_create) \ + V(OBJECT_DEFINE_PROPERTIES, JSFunction, object_define_properties) \ + V(OBJECT_DEFINE_PROPERTY, JSFunction, object_define_property) \ + V(OBJECT_GET_PROTOTYPE_OF, JSFunction, object_get_prototype_of) \ + V(OBJECT_IS_EXTENSIBLE, JSFunction, object_is_extensible) \ + V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \ + V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \ + V(OBJECT_KEYS, JSFunction, object_keys) \ + V(REGEXP_INTERNAL_MATCH, JSFunction, regexp_internal_match) \ + V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \ + V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \ + V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \ + V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \ + V(MATH_FLOOR_INDEX, JSFunction, math_floor) \ + V(MATH_POW_INDEX, JSFunction, math_pow) \ + V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \ + V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \ + promise_internal_constructor) \ + V(IS_PROMISE_INDEX, JSFunction, is_promise) \ + V(PROMISE_THEN_INDEX, JSFunction, promise_then) \ + V(ASYNC_GENERATOR_AWAIT_CAUGHT, JSFunction, async_generator_await_caught) \ + V(ASYNC_GENERATOR_AWAIT_UNCAUGHT, JSFunction, async_generator_await_uncaught) #define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \ V(ARRAY_POP_INDEX, JSFunction, array_pop) \ @@ -114,11 +123,27 @@ enum ContextLookupFlags { V(ARRAY_BUFFER_NOINIT_FUN_INDEX, JSFunction, array_buffer_noinit_fun) \ V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \ V(ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX, Map, async_from_sync_iterator_map) \ + V(ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN, SharedFunctionInfo, \ + async_function_await_reject_shared_fun) \ + V(ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN, SharedFunctionInfo, \ + async_function_await_resolve_shared_fun) \ V(ASYNC_FUNCTION_FUNCTION_INDEX, JSFunction, async_function_constructor) \ V(ASYNC_GENERATOR_FUNCTION_FUNCTION_INDEX, JSFunction, \ async_generator_function_function) \ V(ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN, SharedFunctionInfo, \ async_iterator_value_unwrap_shared_fun) \ + V(ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN, SharedFunctionInfo, \ + async_generator_await_reject_shared_fun) \ + V(ASYNC_GENERATOR_AWAIT_RESOLVE_SHARED_FUN, SharedFunctionInfo, \ + async_generator_await_resolve_shared_fun) \ + V(ASYNC_GENERATOR_YIELD_RESOLVE_SHARED_FUN, SharedFunctionInfo, \ + async_generator_yield_resolve_shared_fun) \ + V(ASYNC_GENERATOR_RETURN_RESOLVE_SHARED_FUN, SharedFunctionInfo, \ + async_generator_return_resolve_shared_fun) \ + V(ASYNC_GENERATOR_RETURN_CLOSED_RESOLVE_SHARED_FUN, SharedFunctionInfo, \ + async_generator_return_closed_resolve_shared_fun) \ + V(ASYNC_GENERATOR_RETURN_CLOSED_REJECT_SHARED_FUN, SharedFunctionInfo, \ + async_generator_return_closed_reject_shared_fun) \ V(ATOMICS_OBJECT, JSObject, atomics_object) \ V(BIGINT_FUNCTION_INDEX, JSFunction, bigint_function) \ V(BIGINT64_ARRAY_FUN_INDEX, JSFunction, bigint64_array_fun) \ diff --git a/src/heap-symbols.h b/src/heap-symbols.h index a6f80f4175..df4923c06a 100644 --- a/src/heap-symbols.h +++ b/src/heap-symbols.h @@ -237,7 +237,6 @@ V(error_script_symbol) \ V(error_start_pos_symbol) \ V(frozen_symbol) \ - V(generator_outer_promise_symbol) \ V(generic_symbol) \ V(home_object_symbol) \ V(intl_initialized_marker_symbol) \ diff --git a/src/interface-descriptors.h b/src/interface-descriptors.h index e31abca1b0..3f047098b1 100644 --- a/src/interface-descriptors.h +++ b/src/interface-descriptors.h @@ -79,7 +79,6 @@ class PlatformInterfaceDescriptor; V(FrameDropperTrampoline) \ V(WasmRuntimeCall) \ V(RunMicrotasks) \ - V(PromiseReactionHandler) \ BUILTIN_LIST_TFS(V) class V8_EXPORT_PRIVATE CallInterfaceDescriptorData { @@ -868,13 +867,6 @@ class RunMicrotasksDescriptor final : public CallInterfaceDescriptor { 0) }; -class PromiseReactionHandlerDescriptor final : public CallInterfaceDescriptor { - public: - DEFINE_PARAMETERS(kArgument, kGenerator) - DECLARE_DEFAULT_DESCRIPTOR(PromiseReactionHandlerDescriptor, - CallInterfaceDescriptor, 2) -}; - #define DEFINE_TFS_BUILTIN_DESCRIPTOR(Name, ...) \ class Name##Descriptor : public CallInterfaceDescriptor { \ public: \ diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc index 5a2248edf1..5f8ebb5896 100644 --- a/src/interpreter/bytecode-generator.cc +++ b/src/interpreter/bytecode-generator.cc @@ -3251,20 +3251,22 @@ void BytecodeGenerator::BuildAwait(Expression* await_expr) { // Await(operand) and suspend. RegisterAllocationScope register_scope(this); - Runtime::FunctionId id; + int await_builtin_context_index; RegisterList args; if (IsAsyncGeneratorFunction(function_kind())) { - id = catch_prediction() == HandlerTable::ASYNC_AWAIT - ? Runtime::kInlineAsyncGeneratorAwaitUncaught - : Runtime::kInlineAsyncGeneratorAwaitCaught; + await_builtin_context_index = + catch_prediction() == HandlerTable::ASYNC_AWAIT + ? Context::ASYNC_GENERATOR_AWAIT_UNCAUGHT + : Context::ASYNC_GENERATOR_AWAIT_CAUGHT; args = register_allocator()->NewRegisterList(2); builder() ->MoveRegister(generator_object(), args[0]) .StoreAccumulatorInRegister(args[1]); } else { - id = catch_prediction() == HandlerTable::ASYNC_AWAIT - ? Runtime::kInlineAsyncFunctionAwaitUncaught - : Runtime::kInlineAsyncFunctionAwaitCaught; + await_builtin_context_index = + catch_prediction() == HandlerTable::ASYNC_AWAIT + ? Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX + : Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX; args = register_allocator()->NewRegisterList(3); builder() ->MoveRegister(generator_object(), args[0]) @@ -3277,7 +3279,7 @@ void BytecodeGenerator::BuildAwait(Expression* await_expr) { builder()->StoreAccumulatorInRegister(args[2]); } - builder()->CallRuntime(id, args); + builder()->CallJSRuntime(await_builtin_context_index, args); } BuildSuspendPoint(await_expr); diff --git a/src/interpreter/interpreter-intrinsics-generator.cc b/src/interpreter/interpreter-intrinsics-generator.cc index 675a8bcccc..0480dec6cc 100644 --- a/src/interpreter/interpreter-intrinsics-generator.cc +++ b/src/interpreter/interpreter-intrinsics-generator.cc @@ -402,30 +402,6 @@ Node* IntrinsicsGenerator::GetImportMetaObject( return return_value.value(); } -Node* IntrinsicsGenerator::AsyncFunctionAwaitCaught( - const InterpreterAssembler::RegListNodePair& args, Node* context) { - return IntrinsicAsBuiltinCall(args, context, - Builtins::kAsyncFunctionAwaitCaught); -} - -Node* IntrinsicsGenerator::AsyncFunctionAwaitUncaught( - const InterpreterAssembler::RegListNodePair& args, Node* context) { - return IntrinsicAsBuiltinCall(args, context, - Builtins::kAsyncFunctionAwaitUncaught); -} - -Node* IntrinsicsGenerator::AsyncGeneratorAwaitCaught( - const InterpreterAssembler::RegListNodePair& args, Node* context) { - return IntrinsicAsBuiltinCall(args, context, - Builtins::kAsyncGeneratorAwaitCaught); -} - -Node* IntrinsicsGenerator::AsyncGeneratorAwaitUncaught( - const InterpreterAssembler::RegListNodePair& args, Node* context) { - return IntrinsicAsBuiltinCall(args, context, - Builtins::kAsyncGeneratorAwaitUncaught); -} - Node* IntrinsicsGenerator::AsyncGeneratorReject( const InterpreterAssembler::RegListNodePair& args, Node* context) { return IntrinsicAsBuiltinCall(args, context, Builtins::kAsyncGeneratorReject); diff --git a/src/interpreter/interpreter-intrinsics.h b/src/interpreter/interpreter-intrinsics.h index 6cdfec2d04..3016183c0b 100644 --- a/src/interpreter/interpreter-intrinsics.h +++ b/src/interpreter/interpreter-intrinsics.h @@ -14,10 +14,6 @@ namespace interpreter { // List of supported intrisics, with upper case name, lower case name and // expected number of arguments (-1 denoting argument count is variable). #define INTRINSICS_LIST(V) \ - V(AsyncFunctionAwaitCaught, async_function_await_caught, 3) \ - V(AsyncFunctionAwaitUncaught, async_function_await_uncaught, 3) \ - V(AsyncGeneratorAwaitCaught, async_generator_await_caught, 2) \ - V(AsyncGeneratorAwaitUncaught, async_generator_await_uncaught, 2) \ V(AsyncGeneratorReject, async_generator_reject, 2) \ V(AsyncGeneratorResolve, async_generator_resolve, 3) \ V(AsyncGeneratorYield, async_generator_yield, 3) \ diff --git a/src/isolate.cc b/src/isolate.cc index 8254e60a19..c97ece3ba4 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -2059,7 +2059,6 @@ void Isolate::PopPromise() { } namespace { - bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate, Handle promise); @@ -2106,27 +2105,29 @@ bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate, } if (promise->status() == Promise::kPending) { - Handle current(promise->reactions(), isolate); - while (!current->IsSmi()) { - Handle current_reaction = - Handle::cast(current); - Handle payload(current_reaction->payload(), isolate); - Handle current_promise; - if (JSPromise::From(payload).ToHandle(¤t_promise)) { - if (current_reaction->reject_handler()->IsCallable()) { - Handle current_handler( - JSReceiver::cast(current_reaction->reject_handler()), isolate); - if (PromiseHandlerCheck(isolate, current_handler, current_promise)) { - return true; - } - } else { - if (InternalPromiseHasUserDefinedRejectHandler(isolate, - current_promise)) { - return true; - } + for (Handle current(promise->reactions(), isolate); + !current->IsSmi();) { + Handle reaction = Handle::cast(current); + Handle promise_or_capability( + reaction->promise_or_capability(), isolate); + Handle promise = Handle::cast( + promise_or_capability->IsJSPromise() + ? promise_or_capability + : handle(Handle::cast(promise_or_capability) + ->promise(), + isolate)); + if (reaction->reject_handler()->IsUndefined(isolate)) { + if (InternalPromiseHasUserDefinedRejectHandler(isolate, promise)) { + return true; + } + } else { + Handle current_handler( + JSReceiver::cast(reaction->reject_handler()), isolate); + if (PromiseHandlerCheck(isolate, current_handler, promise)) { + return true; } } - current = handle(current_reaction->next(), isolate); + current = handle(reaction->next(), isolate); } } diff --git a/src/isolate.h b/src/isolate.h index 7c0153f74a..929403e134 100644 --- a/src/isolate.h +++ b/src/isolate.h @@ -1104,10 +1104,7 @@ class Isolate : private HiddenFactory { bool IsPromiseResolveLookupChainIntact(); // Make sure a lookup of "then" on any JSPromise whose [[Prototype]] is the - // initial %PromisePrototype% yields the initial method. In addition this - // protector also guards the negative lookup of "then" on the intrinsic - // %ObjectPrototype%, meaning that such lookups are guaranteed to yield - // undefined without triggering any side-effects. + // initial %PromisePrototype% yields the initial method. bool IsPromiseThenLookupChainIntact(); bool IsPromiseThenLookupChainIntact(Handle receiver); diff --git a/src/lookup.cc b/src/lookup.cc index 2050114994..a4cca33d6c 100644 --- a/src/lookup.cc +++ b/src/lookup.cc @@ -364,14 +364,7 @@ void LookupIterator::InternalUpdateProtector() { if (!isolate_->IsPromiseThenLookupChainIntact()) return; // Setting the "then" property on any JSPromise instance or on the // initial %PromisePrototype% invalidates the Promise#then protector. - // Also setting the "then" property on the initial %ObjectPrototype% - // invalidates the Promise#then protector, since we use this protector - // to guard the fast-path in AsyncGeneratorResolve, where we can skip - // the ResolvePromise step and go directly to FulfillPromise if we - // know that the Object.prototype doesn't contain a "then" method. if (holder_->IsJSPromise() || - isolate_->IsInAnyContext(*holder_, - Context::INITIAL_OBJECT_PROTOTYPE_INDEX) || isolate_->IsInAnyContext(*holder_, Context::PROMISE_PROTOTYPE_INDEX)) { isolate_->InvalidatePromiseThenProtector(); } diff --git a/src/objects-debug.cc b/src/objects-debug.cc index ba33edb3ab..e12fc75230 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -1224,13 +1224,10 @@ void PromiseReactionJobTask::PromiseReactionJobTaskVerify() { VerifyHeapPointer(context()); CHECK(context()->IsContext()); VerifyHeapPointer(handler()); - VerifyHeapPointer(payload()); - if (handler()->IsCode()) { - CHECK(payload()->IsJSReceiver()); - } else { - CHECK(handler()->IsUndefined(isolate) || handler()->IsCallable()); - CHECK(payload()->IsJSPromise() || payload()->IsPromiseCapability()); - } + CHECK(handler()->IsUndefined(isolate) || handler()->IsCallable()); + VerifyHeapPointer(promise_or_capability()); + CHECK(promise_or_capability()->IsJSPromise() || + promise_or_capability()->IsPromiseCapability()); } void PromiseFulfillReactionJobTask::PromiseFulfillReactionJobTaskVerify() { @@ -1272,18 +1269,14 @@ void PromiseReaction::PromiseReactionVerify() { VerifyPointer(next()); CHECK(next()->IsSmi() || next()->IsPromiseReaction()); VerifyHeapPointer(reject_handler()); + CHECK(reject_handler()->IsUndefined(isolate) || + reject_handler()->IsCallable()); VerifyHeapPointer(fulfill_handler()); - VerifyHeapPointer(payload()); - if (reject_handler()->IsCode()) { - CHECK(fulfill_handler()->IsCode()); - CHECK(payload()->IsJSReceiver()); - } else { - CHECK(reject_handler()->IsUndefined(isolate) || - reject_handler()->IsCallable()); - CHECK(fulfill_handler()->IsUndefined(isolate) || - fulfill_handler()->IsCallable()); - CHECK(payload()->IsJSPromise() || payload()->IsPromiseCapability()); - } + CHECK(fulfill_handler()->IsUndefined(isolate) || + fulfill_handler()->IsCallable()); + VerifyHeapPointer(promise_or_capability()); + CHECK(promise_or_capability()->IsJSPromise() || + promise_or_capability()->IsPromiseCapability()); } void JSPromise::JSPromiseVerify() { diff --git a/src/objects-inl.h b/src/objects-inl.h index ef84df43c4..d9fe22e187 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2291,7 +2291,6 @@ ACCESSORS(JSGlobalObject, global_proxy, JSObject, kGlobalProxyOffset) ACCESSORS(JSGlobalProxy, native_context, Object, kNativeContextOffset) - ACCESSORS(AsyncGeneratorRequest, next, Object, kNextOffset) SMI_ACCESSORS(AsyncGeneratorRequest, resume_mode, kResumeModeOffset) ACCESSORS(AsyncGeneratorRequest, value, Object, kValueOffset) diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 5c14eb7828..99eafbb83f 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -1472,7 +1472,7 @@ void PromiseFulfillReactionJobTask::PromiseFulfillReactionJobTaskPrint( os << "\n - argument: " << Brief(argument()); os << "\n - context: " << Brief(context()); os << "\n - handler: " << Brief(handler()); - os << "\n - payload: " << Brief(payload()); + os << "\n - promise_or_capability: " << Brief(promise_or_capability()); os << "\n"; } @@ -1482,7 +1482,7 @@ void PromiseRejectReactionJobTask::PromiseRejectReactionJobTaskPrint( os << "\n - argument: " << Brief(argument()); os << "\n - context: " << Brief(context()); os << "\n - handler: " << Brief(handler()); - os << "\n - payload: " << Brief(payload()); + os << "\n - promise_or_capability: " << Brief(promise_or_capability()); os << "\n"; } @@ -1509,7 +1509,7 @@ void PromiseReaction::PromiseReactionPrint(std::ostream& os) { // NOLINT os << "\n - next: " << Brief(next()); os << "\n - reject_handler: " << Brief(reject_handler()); os << "\n - fulfill_handler: " << Brief(fulfill_handler()); - os << "\n - payload: " << Brief(payload()); + os << "\n - promise_or_capability: " << Brief(promise_or_capability()); os << "\n"; } diff --git a/src/objects.cc b/src/objects.cc index d21f59c412..16c5c5b294 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -16118,27 +16118,6 @@ MaybeHandle JSPromise::Resolve(Handle promise, return isolate->factory()->undefined_value(); } -// static -MaybeHandle JSPromise::From(Handle object) { - Isolate* const isolate = object->GetIsolate(); - if (object->IsJSPromise()) { - return Handle::cast(object); - } else if (object->IsPromiseCapability()) { - Handle capability = - Handle::cast(object); - if (capability->promise()->IsJSPromise()) { - return handle(JSPromise::cast(capability->promise()), isolate); - } - } else if (object->IsJSGeneratorObject()) { - Handle generator = - Handle::cast(object); - Handle handled_by = JSObject::GetDataProperty( - generator, isolate->factory()->generator_outer_promise_symbol()); - if (handled_by->IsJSPromise()) return Handle::cast(handled_by); - } - return MaybeHandle(); -} - // static Handle JSPromise::TriggerPromiseReactions(Isolate* isolate, Handle reactions, @@ -16178,8 +16157,8 @@ Handle JSPromise::TriggerPromiseReactions(Isolate* isolate, *isolate->native_context()); STATIC_ASSERT(PromiseReaction::kFulfillHandlerOffset == PromiseFulfillReactionJobTask::kHandlerOffset); - STATIC_ASSERT(PromiseReaction::kPayloadOffset == - PromiseFulfillReactionJobTask::kPayloadOffset); + STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset == + PromiseFulfillReactionJobTask::kPromiseOrCapabilityOffset); } else { DisallowHeapAllocation no_gc; HeapObject* handler = reaction->reject_handler(); @@ -16189,8 +16168,8 @@ Handle JSPromise::TriggerPromiseReactions(Isolate* isolate, Handle::cast(task)->set_context( *isolate->native_context()); Handle::cast(task)->set_handler(handler); - STATIC_ASSERT(PromiseReaction::kPayloadOffset == - PromiseRejectReactionJobTask::kPayloadOffset); + STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset == + PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset); } isolate->EnqueueMicrotask(Handle::cast(task)); diff --git a/src/objects/js-promise.h b/src/objects/js-promise.h index 20a0a90131..434bae8933 100644 --- a/src/objects/js-promise.h +++ b/src/objects/js-promise.h @@ -59,12 +59,6 @@ class JSPromise : public JSObject { V8_WARN_UNUSED_RESULT static MaybeHandle Resolve( Handle promise, Handle resolution); - // This is a helper that extracts the JSPromise from the input - // {object}, which is used as a payload for PromiseReaction and - // PromiseReactionJobTask. - V8_WARN_UNUSED_RESULT static MaybeHandle From( - Handle object); - DECL_CAST(JSPromise) // Dispatched behavior. diff --git a/src/objects/promise-inl.h b/src/objects/promise-inl.h index 4283f0aa19..f9fb6110f3 100644 --- a/src/objects/promise-inl.h +++ b/src/objects/promise-inl.h @@ -23,7 +23,8 @@ CAST_ACCESSOR(PromiseResolveThenableJobTask) ACCESSORS(PromiseReaction, next, Object, kNextOffset) ACCESSORS(PromiseReaction, reject_handler, HeapObject, kRejectHandlerOffset) ACCESSORS(PromiseReaction, fulfill_handler, HeapObject, kFulfillHandlerOffset) -ACCESSORS(PromiseReaction, payload, HeapObject, kPayloadOffset) +ACCESSORS(PromiseReaction, promise_or_capability, HeapObject, + kPromiseOrCapabilityOffset) ACCESSORS(PromiseResolveThenableJobTask, context, Context, kContextOffset) ACCESSORS(PromiseResolveThenableJobTask, promise_to_resolve, JSPromise, @@ -34,7 +35,8 @@ ACCESSORS(PromiseResolveThenableJobTask, thenable, JSReceiver, kThenableOffset) ACCESSORS(PromiseReactionJobTask, context, Context, kContextOffset) ACCESSORS(PromiseReactionJobTask, argument, Object, kArgumentOffset); ACCESSORS(PromiseReactionJobTask, handler, HeapObject, kHandlerOffset); -ACCESSORS(PromiseReactionJobTask, payload, HeapObject, kPayloadOffset); +ACCESSORS(PromiseReactionJobTask, promise_or_capability, HeapObject, + kPromiseOrCapabilityOffset); ACCESSORS(PromiseCapability, promise, HeapObject, kPromiseOffset) ACCESSORS(PromiseCapability, resolve, Object, kResolveOffset) diff --git a/src/objects/promise.h b/src/objects/promise.h index 36ef4afe1d..5ff5dac6f3 100644 --- a/src/objects/promise.h +++ b/src/objects/promise.h @@ -26,16 +26,15 @@ class PromiseReactionJobTask : public Microtask { public: DECL_ACCESSORS(argument, Object) DECL_ACCESSORS(context, Context) - // [handler]: This is either a Code object, a Callable or Undefined. DECL_ACCESSORS(handler, HeapObject) - // [payload]: Usually a JSPromise or a PromiseCapability. - DECL_ACCESSORS(payload, HeapObject) + // [promise_or_capability]: Either a JSPromise or a PromiseCapability. + DECL_ACCESSORS(promise_or_capability, HeapObject) static const int kArgumentOffset = Microtask::kHeaderSize; static const int kContextOffset = kArgumentOffset + kPointerSize; static const int kHandlerOffset = kContextOffset + kPointerSize; - static const int kPayloadOffset = kHandlerOffset + kPointerSize; - static const int kSize = kPayloadOffset + kPointerSize; + static const int kPromiseOrCapabilityOffset = kHandlerOffset + kPointerSize; + static const int kSize = kPromiseOrCapabilityOffset + kPointerSize; // Dispatched behavior. DECL_CAST(PromiseReactionJobTask) @@ -121,10 +120,9 @@ class PromiseCapability : public Struct { // of microtasks. So the size of PromiseReaction and the size of the // PromiseReactionJobTask has to be same for this to work. // -// The PromiseReaction::payload field usually holds a JSPromise -// instance (in the fast case of a native promise) or a PromiseCapability -// in case of a custom promise. For await we store the JSGeneratorObject -// here and use custom Code handlers. +// The PromiseReaction::promise_or_capability field can either hold a JSPromise +// instance (in the fast case of a native promise) or a PromiseCapability in +// case of a Promise subclass. // // We need to keep the context in the PromiseReaction so that we can run // the default handlers (in case they are undefined) in the proper context. @@ -138,18 +136,16 @@ class PromiseReaction : public Struct { enum Type { kFulfill, kReject }; DECL_ACCESSORS(next, Object) - // [reject_handler]: This is either a Code object, a Callable or Undefined. DECL_ACCESSORS(reject_handler, HeapObject) - // [fulfill_handler]: This is either a Code object, a Callable or Undefined. DECL_ACCESSORS(fulfill_handler, HeapObject) - // [payload]: Usually a JSPromise or a PromiseCapability. - DECL_ACCESSORS(payload, HeapObject) + DECL_ACCESSORS(promise_or_capability, HeapObject) static const int kNextOffset = Struct::kHeaderSize; static const int kRejectHandlerOffset = kNextOffset + kPointerSize; static const int kFulfillHandlerOffset = kRejectHandlerOffset + kPointerSize; - static const int kPayloadOffset = kFulfillHandlerOffset + kPointerSize; - static const int kSize = kPayloadOffset + kPointerSize; + static const int kPromiseOrCapabilityOffset = + kFulfillHandlerOffset + kPointerSize; + static const int kSize = kPromiseOrCapabilityOffset + kPointerSize; // Dispatched behavior. DECL_CAST(PromiseReaction) diff --git a/src/runtime/runtime-generator.cc b/src/runtime/runtime-generator.cc index e69d334042..3c7c808c30 100644 --- a/src/runtime/runtime-generator.cc +++ b/src/runtime/runtime-generator.cc @@ -70,30 +70,6 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetInputOrDebugPos) { UNREACHABLE(); } -RUNTIME_FUNCTION(Runtime_AsyncFunctionAwaitCaught) { - // Runtime call is implemented in InterpreterIntrinsics and lowered in - // JSIntrinsicLowering - UNREACHABLE(); -} - -RUNTIME_FUNCTION(Runtime_AsyncFunctionAwaitUncaught) { - // Runtime call is implemented in InterpreterIntrinsics and lowered in - // JSIntrinsicLowering - UNREACHABLE(); -} - -RUNTIME_FUNCTION(Runtime_AsyncGeneratorAwaitCaught) { - // Runtime call is implemented in InterpreterIntrinsics and lowered in - // JSIntrinsicLowering - UNREACHABLE(); -} - -RUNTIME_FUNCTION(Runtime_AsyncGeneratorAwaitUncaught) { - // Runtime call is implemented in InterpreterIntrinsics and lowered in - // JSIntrinsicLowering - UNREACHABLE(); -} - RUNTIME_FUNCTION(Runtime_AsyncGeneratorResolve) { // Runtime call is implemented in InterpreterIntrinsics and lowered in // JSIntrinsicLowering diff --git a/src/runtime/runtime-promise.cc b/src/runtime/runtime-promise.cc index b2a7e8bae1..f5b9db3c02 100644 --- a/src/runtime/runtime-promise.cc +++ b/src/runtime/runtime-promise.cc @@ -114,14 +114,13 @@ RUNTIME_FUNCTION(Runtime_PromiseHookInit) { RUNTIME_FUNCTION(Runtime_PromiseHookBefore) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(HeapObject, payload, 0); - Handle promise; - if (JSPromise::From(payload).ToHandle(&promise)) { - if (isolate->debug()->is_active()) isolate->PushPromise(promise); - if (promise->IsJSPromise()) { - isolate->RunPromiseHook(PromiseHookType::kBefore, promise, - isolate->factory()->undefined_value()); - } + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, maybe_promise, 0); + if (!maybe_promise->IsJSPromise()) return isolate->heap()->undefined_value(); + Handle promise = Handle::cast(maybe_promise); + if (isolate->debug()->is_active()) isolate->PushPromise(promise); + if (promise->IsJSPromise()) { + isolate->RunPromiseHook(PromiseHookType::kBefore, promise, + isolate->factory()->undefined_value()); } return isolate->heap()->undefined_value(); } @@ -129,14 +128,13 @@ RUNTIME_FUNCTION(Runtime_PromiseHookBefore) { RUNTIME_FUNCTION(Runtime_PromiseHookAfter) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(HeapObject, payload, 0); - Handle promise; - if (JSPromise::From(payload).ToHandle(&promise)) { - if (isolate->debug()->is_active()) isolate->PopPromise(); - if (promise->IsJSPromise()) { - isolate->RunPromiseHook(PromiseHookType::kAfter, promise, - isolate->factory()->undefined_value()); - } + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, maybe_promise, 0); + if (!maybe_promise->IsJSPromise()) return isolate->heap()->undefined_value(); + Handle promise = Handle::cast(maybe_promise); + if (isolate->debug()->is_active()) isolate->PopPromise(); + if (promise->IsJSPromise()) { + isolate->RunPromiseHook(PromiseHookType::kAfter, promise, + isolate->factory()->undefined_value()); } return isolate->heap()->undefined_value(); } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index b7ef0d0af1..846e82782c 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -224,10 +224,6 @@ namespace internal { F(SetNativeFlag, 1, 1) #define FOR_EACH_INTRINSIC_GENERATOR(F) \ - F(AsyncFunctionAwaitCaught, 3, 1) \ - F(AsyncFunctionAwaitUncaught, 3, 1) \ - F(AsyncGeneratorAwaitCaught, 2, 1) \ - F(AsyncGeneratorAwaitUncaught, 2, 1) \ F(AsyncGeneratorHasCatchHandlerForPC, 1, 1) \ F(AsyncGeneratorReject, 2, 1) \ F(AsyncGeneratorResolve, 3, 1) \ diff --git a/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden b/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden index 6d63516b77..8c3c29f71f 100644 --- a/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden +++ b/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden @@ -39,7 +39,7 @@ bytecodes: [ B(LdaUndefined), B(Star), R(6), B(Mov), R(0), R(5), - B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(5), U8(2), + B(CallJSRuntime), U8(%async_generator_await_uncaught), R(5), U8(2), B(SuspendGenerator), R(0), R(0), U8(5), U8(1), B(ResumeGenerator), R(0), R(0), U8(5), B(Star), R(5), @@ -164,7 +164,7 @@ bytecodes: [ B(LdaUndefined), B(Star), R(6), B(Mov), R(0), R(5), - B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(5), U8(2), + B(CallJSRuntime), U8(%async_generator_await_uncaught), R(5), U8(2), B(SuspendGenerator), R(0), R(0), U8(5), U8(2), B(ResumeGenerator), R(0), R(0), U8(5), B(Star), R(5), @@ -399,7 +399,7 @@ bytecodes: [ B(LdaUndefined), B(Star), R(16), B(Mov), R(2), R(15), - B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(15), U8(2), + B(CallJSRuntime), U8(%async_generator_await_uncaught), R(15), U8(2), B(SuspendGenerator), R(2), R(0), U8(15), U8(2), B(ResumeGenerator), R(2), R(0), U8(15), B(Star), R(15), @@ -573,7 +573,7 @@ bytecodes: [ B(Jump), U8(2), B(Star), R(13), B(Mov), R(0), R(12), - B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(12), U8(2), + B(CallJSRuntime), U8(%async_generator_await_uncaught), R(12), U8(2), /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(1), B(ResumeGenerator), R(0), R(0), U8(12), B(Star), R(12), @@ -591,7 +591,7 @@ bytecodes: [ B(CallRuntime), U16(Runtime::kThrowThrowMethodMissing), R(0), U8(0), B(Star), R(13), B(Mov), R(0), R(12), - B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(12), U8(2), + B(CallJSRuntime), U8(%async_generator_await_uncaught), R(12), U8(2), /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(2), B(ResumeGenerator), R(0), R(0), U8(12), B(Star), R(12), @@ -632,7 +632,7 @@ bytecodes: [ B(LdaUndefined), B(Star), R(6), B(Mov), R(0), R(5), - B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(5), U8(2), + B(CallJSRuntime), U8(%async_generator_await_uncaught), R(5), U8(2), B(SuspendGenerator), R(0), R(0), U8(5), U8(4), B(ResumeGenerator), R(0), R(0), U8(5), B(Star), R(5), diff --git a/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden b/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden index 867e09d6ca..47bcb4aa32 100644 --- a/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden +++ b/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden @@ -53,7 +53,7 @@ bytecodes: [ B(Star), R(21), B(Mov), R(2), R(20), B(Mov), R(11), R(22), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(20), U8(3), + B(CallJSRuntime), U8(%async_function_await_uncaught), R(20), U8(3), /* 40 E> */ B(SuspendGenerator), R(2), R(0), U8(20), U8(0), B(ResumeGenerator), R(2), R(0), U8(20), B(Star), R(20), @@ -136,7 +136,7 @@ bytecodes: [ B(Star), R(21), B(Mov), R(2), R(20), B(Mov), R(11), R(22), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitCaught), R(20), U8(3), + B(CallJSRuntime), U8(%async_function_await_caught), R(20), U8(3), B(SuspendGenerator), R(2), R(0), U8(20), U8(1), B(ResumeGenerator), R(2), R(0), U8(20), B(Star), R(20), @@ -159,7 +159,7 @@ bytecodes: [ B(Star), R(20), B(Mov), R(2), R(19), B(Mov), R(11), R(21), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(19), U8(3), + B(CallJSRuntime), U8(%async_function_await_uncaught), R(19), U8(3), B(SuspendGenerator), R(2), R(0), U8(19), U8(2), B(ResumeGenerator), R(2), R(0), U8(19), B(Star), R(19), @@ -303,7 +303,7 @@ bytecodes: [ B(Star), R(21), B(Mov), R(2), R(20), B(Mov), R(11), R(22), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(20), U8(3), + B(CallJSRuntime), U8(%async_function_await_uncaught), R(20), U8(3), /* 40 E> */ B(SuspendGenerator), R(2), R(0), U8(20), U8(0), B(ResumeGenerator), R(2), R(0), U8(20), B(Star), R(20), @@ -387,7 +387,7 @@ bytecodes: [ B(Star), R(21), B(Mov), R(2), R(20), B(Mov), R(11), R(22), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitCaught), R(20), U8(3), + B(CallJSRuntime), U8(%async_function_await_caught), R(20), U8(3), B(SuspendGenerator), R(2), R(0), U8(20), U8(1), B(ResumeGenerator), R(2), R(0), U8(20), B(Star), R(20), @@ -410,7 +410,7 @@ bytecodes: [ B(Star), R(20), B(Mov), R(2), R(19), B(Mov), R(11), R(21), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(19), U8(3), + B(CallJSRuntime), U8(%async_function_await_uncaught), R(19), U8(3), B(SuspendGenerator), R(2), R(0), U8(19), U8(2), B(ResumeGenerator), R(2), R(0), U8(19), B(Star), R(19), @@ -569,7 +569,7 @@ bytecodes: [ B(Star), R(21), B(Mov), R(2), R(20), B(Mov), R(11), R(22), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(20), U8(3), + B(CallJSRuntime), U8(%async_function_await_uncaught), R(20), U8(3), /* 40 E> */ B(SuspendGenerator), R(2), R(0), U8(20), U8(0), B(ResumeGenerator), R(2), R(0), U8(20), B(Star), R(20), @@ -660,7 +660,7 @@ bytecodes: [ B(Star), R(21), B(Mov), R(2), R(20), B(Mov), R(11), R(22), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitCaught), R(20), U8(3), + B(CallJSRuntime), U8(%async_function_await_caught), R(20), U8(3), B(SuspendGenerator), R(2), R(0), U8(20), U8(1), B(ResumeGenerator), R(2), R(0), U8(20), B(Star), R(20), @@ -683,7 +683,7 @@ bytecodes: [ B(Star), R(20), B(Mov), R(2), R(19), B(Mov), R(11), R(21), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(19), U8(3), + B(CallJSRuntime), U8(%async_function_await_uncaught), R(19), U8(3), B(SuspendGenerator), R(2), R(0), U8(19), U8(2), B(ResumeGenerator), R(2), R(0), U8(19), B(Star), R(19), diff --git a/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden b/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden index 882f61943a..ed0ef4048e 100644 --- a/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden +++ b/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden @@ -1182,7 +1182,7 @@ bytecodes: [ /* 45 S> */ B(Mov), R(2), R(21), B(Mov), R(0), R(22), B(Mov), R(11), R(23), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(21), U8(3), + B(CallJSRuntime), U8(%async_function_await_uncaught), R(21), U8(3), /* 45 E> */ B(SuspendGenerator), R(2), R(0), U8(21), U8(0), B(ResumeGenerator), R(2), R(0), U8(21), B(Star), R(21), diff --git a/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden b/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden index 8be761df37..226fa55039 100644 --- a/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden +++ b/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden @@ -489,7 +489,7 @@ bytecodes: [ /* 52 S> */ B(Mov), R(1), R(7), B(Mov), R(0), R(8), B(Mov), R(2), R(9), - B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(7), U8(3), + B(CallJSRuntime), U8(%async_function_await_uncaught), R(7), U8(3), /* 52 E> */ B(SuspendGenerator), R(1), R(0), U8(7), U8(0), B(ResumeGenerator), R(1), R(0), U8(7), B(Star), R(7), diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index b1d2aced5e..0cc24b1cbd 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -18432,12 +18432,6 @@ TEST(PromiseHook) { CHECK_EQ(v8::Promise::kFulfilled, GetPromise("p")->State()); CHECK_EQ(9, promise_hook_data->promise_hook_count); - promise_hook_data->Reset(); - source = "(async() => await p)();\n"; - - CompileRun(source); - CHECK_EQ(11, promise_hook_data->promise_hook_count); - delete promise_hook_data; isolate->SetPromiseHook(nullptr); } diff --git a/tools/v8heapconst.py b/tools/v8heapconst.py index 3fa1889848..da284eb927 100644 --- a/tools/v8heapconst.py +++ b/tools/v8heapconst.py @@ -265,33 +265,33 @@ KNOWN_MAPS = { ("RO_SPACE", 0x05019): (172, "Tuple2Map"), ("RO_SPACE", 0x05211): (170, "ScriptMap"), ("RO_SPACE", 0x053d9): (162, "InterceptorInfoMap"), - ("RO_SPACE", 0x07b99): (154, "AccessorInfoMap"), - ("RO_SPACE", 0x07da9): (153, "AccessCheckInfoMap"), - ("RO_SPACE", 0x07e11): (155, "AccessorPairMap"), - ("RO_SPACE", 0x07e79): (156, "AliasedArgumentsEntryMap"), - ("RO_SPACE", 0x07ee1): (157, "AllocationMementoMap"), - ("RO_SPACE", 0x07f49): (158, "AllocationSiteMap"), - ("RO_SPACE", 0x07fb1): (159, "AsyncGeneratorRequestMap"), - ("RO_SPACE", 0x08019): (160, "DebugInfoMap"), - ("RO_SPACE", 0x08081): (161, "FunctionTemplateInfoMap"), - ("RO_SPACE", 0x080e9): (163, "InterpreterDataMap"), - ("RO_SPACE", 0x08151): (164, "ModuleInfoEntryMap"), - ("RO_SPACE", 0x081b9): (165, "ModuleMap"), - ("RO_SPACE", 0x08221): (166, "ObjectTemplateInfoMap"), - ("RO_SPACE", 0x08289): (167, "PromiseCapabilityMap"), - ("RO_SPACE", 0x082f1): (168, "PromiseReactionMap"), - ("RO_SPACE", 0x08359): (169, "PrototypeInfoMap"), - ("RO_SPACE", 0x083c1): (171, "StackFrameInfoMap"), - ("RO_SPACE", 0x08429): (173, "Tuple3Map"), - ("RO_SPACE", 0x08491): (174, "WasmCompiledModuleMap"), - ("RO_SPACE", 0x084f9): (175, "WasmDebugInfoMap"), - ("RO_SPACE", 0x08561): (176, "WasmExportedFunctionDataMap"), - ("RO_SPACE", 0x085c9): (177, "WasmSharedModuleDataMap"), - ("RO_SPACE", 0x08631): (178, "CallableTaskMap"), - ("RO_SPACE", 0x08699): (179, "CallbackTaskMap"), - ("RO_SPACE", 0x08701): (180, "PromiseFulfillReactionJobTaskMap"), - ("RO_SPACE", 0x08769): (181, "PromiseRejectReactionJobTaskMap"), - ("RO_SPACE", 0x087d1): (182, "PromiseResolveThenableJobTaskMap"), + ("RO_SPACE", 0x07b79): (154, "AccessorInfoMap"), + ("RO_SPACE", 0x07d89): (153, "AccessCheckInfoMap"), + ("RO_SPACE", 0x07df1): (155, "AccessorPairMap"), + ("RO_SPACE", 0x07e59): (156, "AliasedArgumentsEntryMap"), + ("RO_SPACE", 0x07ec1): (157, "AllocationMementoMap"), + ("RO_SPACE", 0x07f29): (158, "AllocationSiteMap"), + ("RO_SPACE", 0x07f91): (159, "AsyncGeneratorRequestMap"), + ("RO_SPACE", 0x07ff9): (160, "DebugInfoMap"), + ("RO_SPACE", 0x08061): (161, "FunctionTemplateInfoMap"), + ("RO_SPACE", 0x080c9): (163, "InterpreterDataMap"), + ("RO_SPACE", 0x08131): (164, "ModuleInfoEntryMap"), + ("RO_SPACE", 0x08199): (165, "ModuleMap"), + ("RO_SPACE", 0x08201): (166, "ObjectTemplateInfoMap"), + ("RO_SPACE", 0x08269): (167, "PromiseCapabilityMap"), + ("RO_SPACE", 0x082d1): (168, "PromiseReactionMap"), + ("RO_SPACE", 0x08339): (169, "PrototypeInfoMap"), + ("RO_SPACE", 0x083a1): (171, "StackFrameInfoMap"), + ("RO_SPACE", 0x08409): (173, "Tuple3Map"), + ("RO_SPACE", 0x08471): (174, "WasmCompiledModuleMap"), + ("RO_SPACE", 0x084d9): (175, "WasmDebugInfoMap"), + ("RO_SPACE", 0x08541): (176, "WasmExportedFunctionDataMap"), + ("RO_SPACE", 0x085a9): (177, "WasmSharedModuleDataMap"), + ("RO_SPACE", 0x08611): (178, "CallableTaskMap"), + ("RO_SPACE", 0x08679): (179, "CallbackTaskMap"), + ("RO_SPACE", 0x086e1): (180, "PromiseFulfillReactionJobTaskMap"), + ("RO_SPACE", 0x08749): (181, "PromiseRejectReactionJobTaskMap"), + ("RO_SPACE", 0x087b1): (182, "PromiseResolveThenableJobTaskMap"), ("MAP_SPACE", 0x02201): (1057, "ExternalMap"), ("MAP_SPACE", 0x02259): (1072, "JSMessageObjectMap"), }