V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
builtins-async-function-gen.cc
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
3 // found in the LICENSE file.
4 
5 #include "src/builtins/builtins-async-gen.h"
6 #include "src/builtins/builtins-utils-gen.h"
7 #include "src/builtins/builtins.h"
8 #include "src/code-stub-assembler.h"
9 #include "src/objects-inl.h"
10 #include "src/objects/js-generator.h"
11 #include "src/objects/js-promise.h"
12 
13 namespace v8 {
14 namespace internal {
15 
17  public:
19  : AsyncBuiltinsAssembler(state) {}
20 
21  protected:
22  template <typename Descriptor>
23  void AsyncFunctionAwait(const bool is_predicted_as_caught);
24 
25  void AsyncFunctionAwaitResumeClosure(
26  Node* const context, Node* const sent_value,
27  JSGeneratorObject::ResumeMode resume_mode);
28 };
29 
30 void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure(
31  Node* context, Node* sent_value,
32  JSGeneratorObject::ResumeMode resume_mode) {
33  DCHECK(resume_mode == JSGeneratorObject::kNext ||
34  resume_mode == JSGeneratorObject::kThrow);
35 
36  TNode<JSAsyncFunctionObject> async_function_object =
37  CAST(LoadContextElement(context, Context::EXTENSION_INDEX));
38 
39  // Inline version of GeneratorPrototypeNext / GeneratorPrototypeReturn with
40  // unnecessary runtime checks removed.
41 
42  // Ensure that the {async_function_object} is neither closed nor running.
43  CSA_SLOW_ASSERT(
44  this, SmiGreaterThan(
45  LoadObjectField<Smi>(async_function_object,
46  JSGeneratorObject::kContinuationOffset),
47  SmiConstant(JSGeneratorObject::kGeneratorClosed)));
48 
49  // Remember the {resume_mode} for the {async_function_object}.
50  StoreObjectFieldNoWriteBarrier(async_function_object,
51  JSGeneratorObject::kResumeModeOffset,
52  SmiConstant(resume_mode));
53 
54  // Resume the {receiver} using our trampoline.
55  Callable callable = CodeFactory::ResumeGenerator(isolate());
56  CallStub(callable, context, sent_value, async_function_object);
57 
58  // The resulting Promise is a throwaway, so it doesn't matter what it
59  // resolves to. What is important is that we don't end up keeping the
60  // whole chain of intermediate Promises alive by returning the return value
61  // of ResumeGenerator, as that would create a memory leak.
62 }
63 
64 TF_BUILTIN(AsyncFunctionEnter, AsyncFunctionBuiltinsAssembler) {
65  TNode<JSFunction> closure = CAST(Parameter(Descriptor::kClosure));
66  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
67  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
68 
69  // Compute the number of registers and parameters.
70  TNode<SharedFunctionInfo> shared = LoadObjectField<SharedFunctionInfo>(
71  closure, JSFunction::kSharedFunctionInfoOffset);
72  TNode<IntPtrT> formal_parameter_count = ChangeInt32ToIntPtr(
73  LoadObjectField(shared, SharedFunctionInfo::kFormalParameterCountOffset,
74  MachineType::Uint16()));
75  TNode<BytecodeArray> bytecode_array =
76  LoadSharedFunctionInfoBytecodeArray(shared);
77  TNode<IntPtrT> frame_size = ChangeInt32ToIntPtr(LoadObjectField(
78  bytecode_array, BytecodeArray::kFrameSizeOffset, MachineType::Int32()));
79  TNode<IntPtrT> parameters_and_register_length =
80  Signed(IntPtrAdd(WordSar(frame_size, IntPtrConstant(kPointerSizeLog2)),
81  formal_parameter_count));
82 
83  // Allocate space for the promise, the async function object
84  // and the register file.
85  TNode<IntPtrT> size = IntPtrAdd(
86  IntPtrConstant(JSPromise::kSizeWithEmbedderFields +
87  JSAsyncFunctionObject::kSize + FixedArray::kHeaderSize),
88  Signed(WordShl(parameters_and_register_length,
89  IntPtrConstant(kPointerSizeLog2))));
90  TNode<HeapObject> base = AllocateInNewSpace(size);
91 
92  // Initialize the register file.
93  TNode<FixedArray> parameters_and_registers = UncheckedCast<FixedArray>(
94  InnerAllocate(base, JSAsyncFunctionObject::kSize +
95  JSPromise::kSizeWithEmbedderFields));
96  StoreMapNoWriteBarrier(parameters_and_registers, RootIndex::kFixedArrayMap);
97  StoreObjectFieldNoWriteBarrier(parameters_and_registers,
98  FixedArray::kLengthOffset,
99  SmiFromIntPtr(parameters_and_register_length));
100  FillFixedArrayWithValue(HOLEY_ELEMENTS, parameters_and_registers,
101  IntPtrConstant(0), parameters_and_register_length,
102  RootIndex::kUndefinedValue);
103 
104  // Initialize the promise.
105  TNode<Context> native_context = LoadNativeContext(context);
106  TNode<JSFunction> promise_function =
107  CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
108  TNode<Map> promise_map = LoadObjectField<Map>(
109  promise_function, JSFunction::kPrototypeOrInitialMapOffset);
110  TNode<JSPromise> promise = UncheckedCast<JSPromise>(
111  InnerAllocate(base, JSAsyncFunctionObject::kSize));
112  StoreMapNoWriteBarrier(promise, promise_map);
113  StoreObjectFieldRoot(promise, JSPromise::kPropertiesOrHashOffset,
114  RootIndex::kEmptyFixedArray);
115  StoreObjectFieldRoot(promise, JSPromise::kElementsOffset,
116  RootIndex::kEmptyFixedArray);
117  PromiseInit(promise);
118 
119  // Initialize the async function object.
120  TNode<Map> async_function_object_map = CAST(LoadContextElement(
121  native_context, Context::ASYNC_FUNCTION_OBJECT_MAP_INDEX));
122  TNode<JSAsyncFunctionObject> async_function_object =
123  UncheckedCast<JSAsyncFunctionObject>(base);
124  StoreMapNoWriteBarrier(async_function_object, async_function_object_map);
125  StoreObjectFieldRoot(async_function_object,
126  JSAsyncFunctionObject::kPropertiesOrHashOffset,
127  RootIndex::kEmptyFixedArray);
128  StoreObjectFieldRoot(async_function_object,
129  JSAsyncFunctionObject::kElementsOffset,
130  RootIndex::kEmptyFixedArray);
131  StoreObjectFieldNoWriteBarrier(
132  async_function_object, JSAsyncFunctionObject::kFunctionOffset, closure);
133  StoreObjectFieldNoWriteBarrier(
134  async_function_object, JSAsyncFunctionObject::kContextOffset, context);
135  StoreObjectFieldNoWriteBarrier(
136  async_function_object, JSAsyncFunctionObject::kReceiverOffset, receiver);
137  StoreObjectFieldNoWriteBarrier(async_function_object,
138  JSAsyncFunctionObject::kInputOrDebugPosOffset,
139  SmiConstant(0));
140  StoreObjectFieldNoWriteBarrier(async_function_object,
141  JSAsyncFunctionObject::kResumeModeOffset,
142  SmiConstant(JSAsyncFunctionObject::kNext));
143  StoreObjectFieldNoWriteBarrier(
144  async_function_object, JSAsyncFunctionObject::kContinuationOffset,
145  SmiConstant(JSAsyncFunctionObject::kGeneratorExecuting));
146  StoreObjectFieldNoWriteBarrier(
147  async_function_object,
148  JSAsyncFunctionObject::kParametersAndRegistersOffset,
149  parameters_and_registers);
150  StoreObjectFieldNoWriteBarrier(
151  async_function_object, JSAsyncFunctionObject::kPromiseOffset, promise);
152 
153  // Fire promise hooks if enabled and push the Promise under construction
154  // in an async function on the catch prediction stack to handle exceptions
155  // thrown before the first await.
156  Label if_instrumentation(this, Label::kDeferred),
157  if_instrumentation_done(this);
158  Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
159  &if_instrumentation, &if_instrumentation_done);
160  BIND(&if_instrumentation);
161  {
162  CallRuntime(Runtime::kDebugAsyncFunctionEntered, context, promise);
163  Goto(&if_instrumentation_done);
164  }
165  BIND(&if_instrumentation_done);
166 
167  Return(async_function_object);
168 }
169 
170 TF_BUILTIN(AsyncFunctionReject, AsyncFunctionBuiltinsAssembler) {
171  TNode<JSAsyncFunctionObject> async_function_object =
172  CAST(Parameter(Descriptor::kAsyncFunctionObject));
173  TNode<Object> reason = CAST(Parameter(Descriptor::kReason));
174  TNode<Oddball> can_suspend = CAST(Parameter(Descriptor::kCanSuspend));
175  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
176  TNode<JSPromise> promise = LoadObjectField<JSPromise>(
177  async_function_object, JSAsyncFunctionObject::kPromiseOffset);
178 
179  // Reject the {promise} for the given {reason}, disabling the
180  // additional debug event for the rejection since a debug event
181  // already happend for the exception that got us here.
182  CallBuiltin(Builtins::kRejectPromise, context, promise, reason,
183  FalseConstant());
184 
185  Label if_debugging(this, Label::kDeferred);
186  GotoIf(HasAsyncEventDelegate(), &if_debugging);
187  GotoIf(IsDebugActive(), &if_debugging);
188  Return(promise);
189 
190  BIND(&if_debugging);
191  TailCallRuntime(Runtime::kDebugAsyncFunctionFinished, context, can_suspend,
192  promise);
193 }
194 
195 TF_BUILTIN(AsyncFunctionResolve, AsyncFunctionBuiltinsAssembler) {
196  TNode<JSAsyncFunctionObject> async_function_object =
197  CAST(Parameter(Descriptor::kAsyncFunctionObject));
198  TNode<Object> value = CAST(Parameter(Descriptor::kValue));
199  TNode<Oddball> can_suspend = CAST(Parameter(Descriptor::kCanSuspend));
200  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
201  TNode<JSPromise> promise = LoadObjectField<JSPromise>(
202  async_function_object, JSAsyncFunctionObject::kPromiseOffset);
203 
204  CallBuiltin(Builtins::kResolvePromise, context, promise, value);
205 
206  Label if_debugging(this, Label::kDeferred);
207  GotoIf(HasAsyncEventDelegate(), &if_debugging);
208  GotoIf(IsDebugActive(), &if_debugging);
209  Return(promise);
210 
211  BIND(&if_debugging);
212  TailCallRuntime(Runtime::kDebugAsyncFunctionFinished, context, can_suspend,
213  promise);
214 }
215 
216 // AsyncFunctionReject and AsyncFunctionResolve are both required to return
217 // the promise instead of the result of RejectPromise or ResolvePromise
218 // respectively from a lazy deoptimization.
219 TF_BUILTIN(AsyncFunctionLazyDeoptContinuation, AsyncFunctionBuiltinsAssembler) {
220  TNode<JSPromise> promise = CAST(Parameter(Descriptor::kPromise));
221  Return(promise);
222 }
223 
224 TF_BUILTIN(AsyncFunctionAwaitRejectClosure, AsyncFunctionBuiltinsAssembler) {
225  CSA_ASSERT_JS_ARGC_EQ(this, 1);
226  Node* const sentError = Parameter(Descriptor::kSentError);
227  Node* const context = Parameter(Descriptor::kContext);
228 
229  AsyncFunctionAwaitResumeClosure(context, sentError,
230  JSGeneratorObject::kThrow);
231  Return(UndefinedConstant());
232 }
233 
234 TF_BUILTIN(AsyncFunctionAwaitResolveClosure, AsyncFunctionBuiltinsAssembler) {
235  CSA_ASSERT_JS_ARGC_EQ(this, 1);
236  Node* const sentValue = Parameter(Descriptor::kSentValue);
237  Node* const context = Parameter(Descriptor::kContext);
238 
239  AsyncFunctionAwaitResumeClosure(context, sentValue, JSGeneratorObject::kNext);
240  Return(UndefinedConstant());
241 }
242 
243 // ES#abstract-ops-async-function-await
244 // AsyncFunctionAwait ( value )
245 // Shared logic for the core of await. The parser desugars
246 // await value
247 // into
248 // yield AsyncFunctionAwait{Caught,Uncaught}(.generator_object, value)
249 // The 'value' parameter is the value; the .generator_object stands in
250 // for the asyncContext.
251 template <typename Descriptor>
252 void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
253  const bool is_predicted_as_caught) {
254  TNode<JSAsyncFunctionObject> async_function_object =
255  CAST(Parameter(Descriptor::kAsyncFunctionObject));
256  TNode<Object> value = CAST(Parameter(Descriptor::kValue));
257  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
258 
259  Node* outer_promise = LoadObjectField(async_function_object,
260  JSAsyncFunctionObject::kPromiseOffset);
261 
262  Label after_debug_hook(this), call_debug_hook(this, Label::kDeferred);
263  GotoIf(HasAsyncEventDelegate(), &call_debug_hook);
264  Goto(&after_debug_hook);
265  BIND(&after_debug_hook);
266 
267  Await(context, async_function_object, value, outer_promise,
268  Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN,
269  Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN,
270  is_predicted_as_caught);
271 
272  // Return outer promise to avoid adding an load of the outer promise before
273  // suspending in BytecodeGenerator.
274  Return(outer_promise);
275 
276  BIND(&call_debug_hook);
277  CallRuntime(Runtime::kDebugAsyncFunctionSuspended, context, outer_promise);
278  Goto(&after_debug_hook);
279 }
280 
281 // Called by the parser from the desugaring of 'await' when catch
282 // prediction indicates that there is a locally surrounding catch block.
283 TF_BUILTIN(AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) {
284  static const bool kIsPredictedAsCaught = true;
285  AsyncFunctionAwait<Descriptor>(kIsPredictedAsCaught);
286 }
287 
288 // Called by the parser from the desugaring of 'await' when catch
289 // prediction indicates no locally surrounding catch block.
290 TF_BUILTIN(AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) {
291  static const bool kIsPredictedAsCaught = false;
292  AsyncFunctionAwait<Descriptor>(kIsPredictedAsCaught);
293 }
294 
295 } // namespace internal
296 } // namespace v8
Definition: libplatform.h:13