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 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