@@ -21,18 +21,37 @@ class AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler {
21
21
Node* const awaited, Node* const outer_promise,
22
22
const bool is_predicted_as_caught);
23
23
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);
27
27
};
28
28
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,
31
43
JSGeneratorObject::ResumeMode resume_mode) {
32
- CSA_ASSERT (this , IsJSGeneratorObject (generator));
33
44
DCHECK (resume_mode == JSGeneratorObject::kNext ||
34
45
resume_mode == JSGeneratorObject::kThrow );
35
46
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
+
36
55
// Ensure that the generator is neither closed nor running.
37
56
CSA_SLOW_ASSERT (
38
57
this ,
@@ -47,23 +66,31 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResume(
47
66
48
67
// Resume the {receiver} using our trampoline.
49
68
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.
51
75
}
52
76
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 );
56
80
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 ());
59
85
}
60
86
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 );
64
90
Node* const context = Parameter (Descriptor::kContext );
65
- AsyncFunctionAwaitResume (context, argument, generator,
66
- JSGeneratorObject::kThrow );
91
+
92
+ AsyncFunctionAwaitResumeClosure (context, sentValue, JSGeneratorObject::kNext );
93
+ Return (UndefinedConstant ());
67
94
}
68
95
69
96
// ES#abstract-ops-async-function-await
@@ -78,12 +105,25 @@ TF_BUILTIN(AsyncFunctionAwaitReject, AsyncFunctionBuiltinsAssembler) {
78
105
void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait (
79
106
Node* const context, Node* const generator, Node* const awaited,
80
107
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);
87
127
88
128
// Return outer promise to avoid adding an load of the outer promise before
89
129
// suspending in BytecodeGenerator.
@@ -93,28 +133,30 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
93
133
// Called by the parser from the desugaring of 'await' when catch
94
134
// prediction indicates that there is a locally surrounding catch block.
95
135
TF_BUILTIN (AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) {
136
+ CSA_ASSERT_JS_ARGC_EQ (this , 3 );
96
137
Node* const generator = Parameter (Descriptor::kGenerator );
97
- Node* const value = Parameter (Descriptor::kValue );
138
+ Node* const awaited = Parameter (Descriptor::kAwaited );
98
139
Node* const outer_promise = Parameter (Descriptor::kOuterPromise );
99
140
Node* const context = Parameter (Descriptor::kContext );
100
141
101
142
static const bool kIsPredictedAsCaught = true ;
102
143
103
- AsyncFunctionAwait (context, generator, value , outer_promise,
144
+ AsyncFunctionAwait (context, generator, awaited , outer_promise,
104
145
kIsPredictedAsCaught );
105
146
}
106
147
107
148
// Called by the parser from the desugaring of 'await' when catch
108
149
// prediction indicates no locally surrounding catch block.
109
150
TF_BUILTIN (AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) {
151
+ CSA_ASSERT_JS_ARGC_EQ (this , 3 );
110
152
Node* const generator = Parameter (Descriptor::kGenerator );
111
- Node* const value = Parameter (Descriptor::kValue );
153
+ Node* const awaited = Parameter (Descriptor::kAwaited );
112
154
Node* const outer_promise = Parameter (Descriptor::kOuterPromise );
113
155
Node* const context = Parameter (Descriptor::kContext );
114
156
115
157
static const bool kIsPredictedAsCaught = false ;
116
158
117
- AsyncFunctionAwait (context, generator, value , outer_promise,
159
+ AsyncFunctionAwait (context, generator, awaited , outer_promise,
118
160
kIsPredictedAsCaught );
119
161
}
120
162
0 commit comments