@@ -21,18 +21,37 @@ class AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler {
2121 Node* const awaited, Node* const outer_promise,
2222 const bool is_predicted_as_caught);
2323
24- void AsyncFunctionAwaitResume (Node* const context, Node* const argument,
25- Node* const generator ,
26- JSGeneratorObject::ResumeMode resume_mode);
24+ void AsyncFunctionAwaitResumeClosure (
25+ Node* const context, Node* const sent_value ,
26+ JSGeneratorObject::ResumeMode resume_mode);
2727};
2828
29- void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResume (
30- Node* const context, Node* const argument, Node* const generator,
29+ namespace {
30+
31+ // Describe fields of Context associated with AsyncFunctionAwait resume
32+ // closures.
33+ // TODO(jgruber): Refactor to reuse code for upcoming async-generators.
34+ class AwaitContext {
35+ public:
36+ enum Fields { kGeneratorSlot = Context::MIN_CONTEXT_SLOTS, kLength };
37+ };
38+
39+ } // anonymous namespace
40+
41+ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure (
42+ Node* context, Node* sent_value,
3143 JSGeneratorObject::ResumeMode resume_mode) {
32- CSA_ASSERT (this , IsJSGeneratorObject (generator));
3344 DCHECK (resume_mode == JSGeneratorObject::kNext ||
3445 resume_mode == JSGeneratorObject::kThrow );
3546
47+ Node* const generator =
48+ LoadContextElement (context, AwaitContext::kGeneratorSlot );
49+ CSA_SLOW_ASSERT (this , HasInstanceType (generator, JS_GENERATOR_OBJECT_TYPE));
50+
51+ // Inline version of GeneratorPrototypeNext / GeneratorPrototypeReturn with
52+ // unnecessary runtime checks removed.
53+ // TODO(jgruber): Refactor to reuse code from builtins-generator.cc.
54+
3655 // Ensure that the generator is neither closed nor running.
3756 CSA_SLOW_ASSERT (
3857 this ,
@@ -47,23 +66,31 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResume(
4766
4867 // Resume the {receiver} using our trampoline.
4968 Callable callable = CodeFactory::ResumeGenerator (isolate ());
50- TailCallStub (callable, context, argument, generator);
69+ CallStub (callable, context, sent_value, generator);
70+
71+ // The resulting Promise is a throwaway, so it doesn't matter what it
72+ // resolves to. What is important is that we don't end up keeping the
73+ // whole chain of intermediate Promises alive by returning the return value
74+ // of ResumeGenerator, as that would create a memory leak.
5175}
5276
53- TF_BUILTIN (AsyncFunctionAwaitFulfill , AsyncFunctionBuiltinsAssembler) {
54- Node* const argument = Parameter (Descriptor:: kArgument );
55- Node* const generator = Parameter (Descriptor::kGenerator );
77+ TF_BUILTIN (AsyncFunctionAwaitRejectClosure , AsyncFunctionBuiltinsAssembler) {
78+ CSA_ASSERT_JS_ARGC_EQ ( this , 1 );
79+ Node* const sentError = Parameter (Descriptor::kSentError );
5680 Node* const context = Parameter (Descriptor::kContext );
57- AsyncFunctionAwaitResume (context, argument, generator,
58- JSGeneratorObject::kNext );
81+
82+ AsyncFunctionAwaitResumeClosure (context, sentError,
83+ JSGeneratorObject::kThrow );
84+ Return (UndefinedConstant ());
5985}
6086
61- TF_BUILTIN (AsyncFunctionAwaitReject , AsyncFunctionBuiltinsAssembler) {
62- Node* const argument = Parameter (Descriptor:: kArgument );
63- Node* const generator = Parameter (Descriptor::kGenerator );
87+ TF_BUILTIN (AsyncFunctionAwaitResolveClosure , AsyncFunctionBuiltinsAssembler) {
88+ CSA_ASSERT_JS_ARGC_EQ ( this , 1 );
89+ Node* const sentValue = Parameter (Descriptor::kSentValue );
6490 Node* const context = Parameter (Descriptor::kContext );
65- AsyncFunctionAwaitResume (context, argument, generator,
66- JSGeneratorObject::kThrow );
91+
92+ AsyncFunctionAwaitResumeClosure (context, sentValue, JSGeneratorObject::kNext );
93+ Return (UndefinedConstant ());
6794}
6895
6996// ES#abstract-ops-async-function-await
@@ -78,12 +105,25 @@ TF_BUILTIN(AsyncFunctionAwaitReject, AsyncFunctionBuiltinsAssembler) {
78105void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait (
79106 Node* const context, Node* const generator, Node* const awaited,
80107 Node* const outer_promise, const bool is_predicted_as_caught) {
81- CSA_SLOW_ASSERT (this , IsJSGeneratorObject (generator));
82- CSA_SLOW_ASSERT (this , IsJSPromise (outer_promise));
83-
84- Await (context, generator, awaited, outer_promise,
85- Builtins::kAsyncFunctionAwaitFulfill ,
86- Builtins::kAsyncFunctionAwaitReject , is_predicted_as_caught);
108+ CSA_SLOW_ASSERT (this , HasInstanceType (generator, JS_GENERATOR_OBJECT_TYPE));
109+ CSA_SLOW_ASSERT (this , HasInstanceType (outer_promise, JS_PROMISE_TYPE));
110+
111+ ContextInitializer init_closure_context = [&](Node* context) {
112+ StoreContextElementNoWriteBarrier (context, AwaitContext::kGeneratorSlot ,
113+ generator);
114+ };
115+
116+ // TODO(jgruber): AsyncBuiltinsAssembler::Await currently does not reuse
117+ // the awaited promise if it is already a promise. Reuse is non-spec compliant
118+ // but part of our old behavior gives us a couple of percent
119+ // performance boost.
120+ // TODO(jgruber): Use a faster specialized version of
121+ // InternalPerformPromiseThen.
122+
123+ Await (context, generator, awaited, outer_promise, AwaitContext::kLength ,
124+ init_closure_context, Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN,
125+ Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN,
126+ is_predicted_as_caught);
87127
88128 // Return outer promise to avoid adding an load of the outer promise before
89129 // suspending in BytecodeGenerator.
@@ -93,28 +133,30 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
93133// Called by the parser from the desugaring of 'await' when catch
94134// prediction indicates that there is a locally surrounding catch block.
95135TF_BUILTIN (AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) {
136+ CSA_ASSERT_JS_ARGC_EQ (this , 3 );
96137 Node* const generator = Parameter (Descriptor::kGenerator );
97- Node* const value = Parameter (Descriptor::kValue );
138+ Node* const awaited = Parameter (Descriptor::kAwaited );
98139 Node* const outer_promise = Parameter (Descriptor::kOuterPromise );
99140 Node* const context = Parameter (Descriptor::kContext );
100141
101142 static const bool kIsPredictedAsCaught = true ;
102143
103- AsyncFunctionAwait (context, generator, value , outer_promise,
144+ AsyncFunctionAwait (context, generator, awaited , outer_promise,
104145 kIsPredictedAsCaught );
105146}
106147
107148// Called by the parser from the desugaring of 'await' when catch
108149// prediction indicates no locally surrounding catch block.
109150TF_BUILTIN (AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) {
151+ CSA_ASSERT_JS_ARGC_EQ (this , 3 );
110152 Node* const generator = Parameter (Descriptor::kGenerator );
111- Node* const value = Parameter (Descriptor::kValue );
153+ Node* const awaited = Parameter (Descriptor::kAwaited );
112154 Node* const outer_promise = Parameter (Descriptor::kOuterPromise );
113155 Node* const context = Parameter (Descriptor::kContext );
114156
115157 static const bool kIsPredictedAsCaught = false ;
116158
117- AsyncFunctionAwait (context, generator, value , outer_promise,
159+ AsyncFunctionAwait (context, generator, awaited , outer_promise,
118160 kIsPredictedAsCaught );
119161}
120162
0 commit comments