OLD | NEW |
---|---|
1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-promise.h" | 5 #include "src/builtins/builtins-async.h" |
6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
7 #include "src/builtins/builtins.h" | 7 #include "src/builtins/builtins.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
11 namespace internal { | 11 namespace internal { |
12 | 12 |
13 typedef compiler::Node Node; | 13 typedef compiler::Node Node; |
14 typedef CodeStubAssembler::ParameterMode ParameterMode; | 14 typedef CodeStubAssembler::ParameterMode ParameterMode; |
15 typedef compiler::CodeAssemblerState CodeAssemblerState; | 15 typedef compiler::CodeAssemblerState CodeAssemblerState; |
16 | 16 |
17 class AsyncFunctionBuiltinsAssembler : public PromiseBuiltinsAssembler { | 17 class AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler { |
18 public: | 18 public: |
19 explicit AsyncFunctionBuiltinsAssembler(CodeAssemblerState* state) | 19 explicit AsyncFunctionBuiltinsAssembler(CodeAssemblerState* state) |
20 : PromiseBuiltinsAssembler(state) {} | 20 : AsyncBuiltinsAssembler(state) {} |
21 | |
22 protected: | |
23 void AsyncFunctionAwait(Node* const context, Node* const generator, | |
24 Node* const awaited, Node* const outer_promise, | |
25 const bool is_predicted_as_caught); | |
26 | |
27 void AsyncFunctionAwaitResumeClosure( | |
28 Node* const context, Node* const sent_value, | |
29 JSGeneratorObject::ResumeMode resume_mode); | |
21 }; | 30 }; |
22 | 31 |
32 namespace { | |
33 | |
34 // Describe fields of Context associated with AsyncFunctionAwait resume | |
35 // closures. | |
36 // TODO(jgruber): Refactor to reuse code for upcoming async-generators. | |
37 class AwaitContext { | |
38 public: | |
39 enum Fields { kGeneratorSlot = Context::MIN_CONTEXT_SLOTS, kLength }; | |
40 }; | |
41 | |
42 } // anonymous namespace | |
43 | |
44 void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure( | |
45 Node* context, Node* sent_value, | |
46 JSGeneratorObject::ResumeMode resume_mode) { | |
47 DCHECK(resume_mode == JSGeneratorObject::kNext || | |
48 resume_mode == JSGeneratorObject::kThrow); | |
49 | |
50 Node* const generator = | |
51 LoadContextElement(context, AwaitContext::kGeneratorSlot); | |
52 CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE)); | |
53 | |
54 // Inline version of GeneratorPrototypeNext / GeneratorPrototypeReturn with | |
55 // unnecessary runtime checks removed. | |
56 // TODO(jgruber): Refactor to reuse code from builtins-generator.cc. | |
57 | |
58 // Ensure that the generator is neither closed nor running. | |
59 CSA_SLOW_ASSERT( | |
60 this, | |
61 SmiGreaterThan( | |
62 LoadObjectField(generator, JSGeneratorObject::kContinuationOffset), | |
63 SmiConstant(JSGeneratorObject::kGeneratorClosed))); | |
64 | |
65 // Resume the {receiver} using our trampoline. | |
66 Callable callable = CodeFactory::ResumeGenerator(isolate()); | |
67 CallStub(callable, context, sent_value, generator, SmiConstant(resume_mode)); | |
jgruber
2017/01/19 16:12:00
GeneratorPrototype{Next,Return} basically boils do
| |
68 | |
69 // The resulting Promise is a throwaway, so it doesn't matter what it | |
70 // resolves to. What is important is that we don't end up keeping the | |
71 // whole chain of intermediate Promises alive by returning the return value | |
72 // of ResumeGenerator, as that would create a memory leak. | |
73 } | |
74 | |
75 TF_BUILTIN(AsyncFunctionAwaitRejectClosure, AsyncFunctionBuiltinsAssembler) { | |
76 CSA_ASSERT_JS_ARGC_EQ(this, 1); | |
77 Node* const sentError = Parameter(1); | |
78 Node* const context = Parameter(4); | |
79 | |
80 AsyncFunctionAwaitResumeClosure(context, sentError, | |
81 JSGeneratorObject::kThrow); | |
82 Return(UndefinedConstant()); | |
83 } | |
84 | |
85 TF_BUILTIN(AsyncFunctionAwaitResolveClosure, AsyncFunctionBuiltinsAssembler) { | |
86 CSA_ASSERT_JS_ARGC_EQ(this, 1); | |
87 Node* const sentValue = Parameter(1); | |
88 Node* const context = Parameter(4); | |
89 | |
90 AsyncFunctionAwaitResumeClosure(context, sentValue, JSGeneratorObject::kNext); | |
91 Return(UndefinedConstant()); | |
92 } | |
93 | |
94 // ES#abstract-ops-async-function-await | |
95 // AsyncFunctionAwait ( value ) | |
96 // Shared logic for the core of await. The parser desugars | |
97 // await awaited | |
98 // into | |
99 // yield AsyncFunctionAwait{Caught,Uncaught}(.generator, awaited, .promise) | |
100 // The 'awaited' parameter is the value; the generator stands in | |
101 // for the asyncContext, and .promise is the larger promise under | |
102 // construction by the enclosing async function. | |
103 void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait( | |
104 Node* const context, Node* const generator, Node* const awaited, | |
105 Node* const outer_promise, const bool is_predicted_as_caught) { | |
106 CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE)); | |
107 CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE)); | |
108 | |
109 NodeGenerator1 create_closure_context = [&](Node* native_context) -> Node* { | |
110 Node* const context = | |
111 CreatePromiseContext(native_context, AwaitContext::kLength); | |
112 StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot, | |
113 generator); | |
114 return context; | |
115 }; | |
116 | |
117 // TODO(jgruber): AsyncBuiltinsAssembler::Await currently does not reuse | |
118 // the awaited promise if it is already a promise. Reuse is non-spec compliant | |
119 // but part of our old behavior gives us a couple of percent | |
120 // performance boost. | |
121 // TODO(jgruber): Use a faster specialized version of | |
jgruber
2017/01/19 16:12:00
I think caitp has already done some work on this.
| |
122 // InternalPerformPromiseThen. | |
123 | |
124 Node* const result = Await( | |
125 context, generator, awaited, outer_promise, create_closure_context, | |
126 Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN, | |
127 Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN, is_predicted_as_caught); | |
128 | |
129 Return(result); | |
130 } | |
131 | |
132 // Called by the parser from the desugaring of 'await' when catch | |
133 // prediction indicates that there is a locally surrounding catch block. | |
134 TF_BUILTIN(AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) { | |
135 CSA_ASSERT_JS_ARGC_EQ(this, 3); | |
136 Node* const generator = Parameter(1); | |
137 Node* const awaited = Parameter(2); | |
138 Node* const outer_promise = Parameter(3); | |
139 Node* const context = Parameter(6); | |
140 | |
141 static const bool kIsPredictedAsCaught = true; | |
142 | |
143 AsyncFunctionAwait(context, generator, awaited, outer_promise, | |
144 kIsPredictedAsCaught); | |
145 } | |
146 | |
147 // Called by the parser from the desugaring of 'await' when catch | |
148 // prediction indicates no locally surrounding catch block. | |
149 TF_BUILTIN(AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) { | |
150 CSA_ASSERT_JS_ARGC_EQ(this, 3); | |
151 Node* const generator = Parameter(1); | |
152 Node* const awaited = Parameter(2); | |
153 Node* const outer_promise = Parameter(3); | |
154 Node* const context = Parameter(6); | |
155 | |
156 static const bool kIsPredictedAsCaught = false; | |
157 | |
158 AsyncFunctionAwait(context, generator, awaited, outer_promise, | |
159 kIsPredictedAsCaught); | |
160 } | |
161 | |
23 TF_BUILTIN(AsyncFunctionPromiseCreate, AsyncFunctionBuiltinsAssembler) { | 162 TF_BUILTIN(AsyncFunctionPromiseCreate, AsyncFunctionBuiltinsAssembler) { |
24 CSA_ASSERT_JS_ARGC_EQ(this, 0); | 163 CSA_ASSERT_JS_ARGC_EQ(this, 0); |
25 Node* const context = Parameter(3); | 164 Node* const context = Parameter(3); |
26 | 165 |
27 Node* const promise = AllocateAndInitJSPromise(context); | 166 Node* const promise = AllocateAndInitJSPromise(context); |
28 | 167 |
29 Label if_is_debug_active(this, Label::kDeferred); | 168 Label if_is_debug_active(this, Label::kDeferred); |
30 GotoIf(IsDebugActive(), &if_is_debug_active); | 169 GotoIf(IsDebugActive(), &if_is_debug_active); |
31 | 170 |
32 // Early exit if debug is not active. | 171 // Early exit if debug is not active. |
(...skipping 26 matching lines...) Expand all Loading... | |
59 { | 198 { |
60 // Pop the Promise under construction in an async function on | 199 // Pop the Promise under construction in an async function on |
61 // from catch prediction stack. | 200 // from catch prediction stack. |
62 CallRuntime(Runtime::kDebugPopPromise, context); | 201 CallRuntime(Runtime::kDebugPopPromise, context); |
63 Return(promise); | 202 Return(promise); |
64 } | 203 } |
65 } | 204 } |
66 | 205 |
67 } // namespace internal | 206 } // namespace internal |
68 } // namespace v8 | 207 } // namespace v8 |
OLD | NEW |