1 // Copyright 2016 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.h"
6 #include "src/builtins/builtins-utils.h"
7 #include "src/builtins/builtins.h"
8 #include "src/code-factory.h"
9 #include "src/code-stub-assembler.h"
10 #include "src/frames-inl.h"
11
12 namespace v8 {
13 namespace internal {
14
Await(Node * context,Node * generator,Node * value,Node * outer_promise,const NodeGenerator1 & create_closure_context,int on_resolve_context_index,int on_reject_context_index,bool is_predicted_as_caught)15 Node* AsyncBuiltinsAssembler::Await(
16 Node* context, Node* generator, Node* value, Node* outer_promise,
17 const NodeGenerator1& create_closure_context, int on_resolve_context_index,
18 int on_reject_context_index, bool is_predicted_as_caught) {
19 // Let promiseCapability be ! NewPromiseCapability(%Promise%).
20 Node* const wrapped_value = AllocateAndInitJSPromise(context);
21
22 // Perform ! Call(promiseCapability.[[Resolve]], undefined, « promise »).
23 InternalResolvePromise(context, wrapped_value, value);
24
25 Node* const native_context = LoadNativeContext(context);
26
27 Node* const closure_context = create_closure_context(native_context);
28 Node* const map = LoadContextElement(
29 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
30
31 // Load and allocate on_resolve closure
32 Node* const on_resolve_shared_fun =
33 LoadContextElement(native_context, on_resolve_context_index);
34 CSA_SLOW_ASSERT(
35 this, HasInstanceType(on_resolve_shared_fun, SHARED_FUNCTION_INFO_TYPE));
36 Node* const on_resolve = AllocateFunctionWithMapAndContext(
37 map, on_resolve_shared_fun, closure_context);
38
39 // Load and allocate on_reject closure
40 Node* const on_reject_shared_fun =
41 LoadContextElement(native_context, on_reject_context_index);
42 CSA_SLOW_ASSERT(
43 this, HasInstanceType(on_reject_shared_fun, SHARED_FUNCTION_INFO_TYPE));
44 Node* const on_reject = AllocateFunctionWithMapAndContext(
45 map, on_reject_shared_fun, closure_context);
46
47 Node* const throwaway_promise =
48 AllocateAndInitJSPromise(context, wrapped_value);
49
50 // The Promise will be thrown away and not handled, but it shouldn't trigger
51 // unhandled reject events as its work is done
52 PromiseSetHasHandler(throwaway_promise);
53
54 Label do_perform_promise_then(this);
55 GotoIfNot(IsDebugActive(), &do_perform_promise_then);
56 {
57 Label common(this);
58 GotoIf(TaggedIsSmi(value), &common);
59 GotoIfNot(HasInstanceType(value, JS_PROMISE_TYPE), &common);
60 {
61 // Mark the reject handler callback to be a forwarding edge, rather
62 // than a meaningful catch handler
63 Node* const key =
64 HeapConstant(factory()->promise_forwarding_handler_symbol());
65 CallRuntime(Runtime::kSetProperty, context, on_reject, key,
66 TrueConstant(), SmiConstant(STRICT));
67
68 if (is_predicted_as_caught) PromiseSetHandledHint(value);
69 }
70
71 Goto(&common);
72 Bind(&common);
73 // Mark the dependency to outer Promise in case the throwaway Promise is
74 // found on the Promise stack
75 CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE));
76
77 Node* const key = HeapConstant(factory()->promise_handled_by_symbol());
78 CallRuntime(Runtime::kSetProperty, context, throwaway_promise, key,
79 outer_promise, SmiConstant(STRICT));
80 }
81
82 Goto(&do_perform_promise_then);
83 Bind(&do_perform_promise_then);
84 InternalPerformPromiseThen(context, wrapped_value, on_resolve, on_reject,
85 throwaway_promise, UndefinedConstant(),
86 UndefinedConstant());
87
88 return wrapped_value;
89 }
90
91 } // namespace internal
92 } // namespace v8
93