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(function(global, utils, extrasUtils) { 6 7"use strict"; 8 9%CheckIsBootstrapping(); 10 11// ------------------------------------------------------------------- 12// Imports 13 14var AsyncFunctionNext; 15var AsyncFunctionThrow; 16var GlobalPromise; 17var IsPromise; 18var NewPromiseCapability; 19var PerformPromiseThen; 20var PromiseCreate; 21var PromiseNextMicrotaskID; 22var RejectPromise; 23var ResolvePromise; 24 25utils.Import(function(from) { 26 AsyncFunctionNext = from.AsyncFunctionNext; 27 AsyncFunctionThrow = from.AsyncFunctionThrow; 28 GlobalPromise = from.GlobalPromise; 29 IsPromise = from.IsPromise; 30 NewPromiseCapability = from.NewPromiseCapability; 31 PerformPromiseThen = from.PerformPromiseThen; 32 PromiseCreate = from.PromiseCreate; 33 RejectPromise = from.RejectPromise; 34 ResolvePromise = from.ResolvePromise; 35}); 36 37var promiseAsyncStackIDSymbol = 38 utils.ImportNow("promise_async_stack_id_symbol"); 39var promiseHandledBySymbol = 40 utils.ImportNow("promise_handled_by_symbol"); 41var promiseForwardingHandlerSymbol = 42 utils.ImportNow("promise_forwarding_handler_symbol"); 43var promiseHandledHintSymbol = 44 utils.ImportNow("promise_handled_hint_symbol"); 45var promiseHasHandlerSymbol = 46 utils.ImportNow("promise_has_handler_symbol"); 47 48// ------------------------------------------------------------------- 49 50function PromiseCastResolved(value) { 51 if (IsPromise(value)) { 52 return value; 53 } else { 54 var promise = PromiseCreate(); 55 ResolvePromise(promise, value); 56 return promise; 57 } 58} 59 60// ES#abstract-ops-async-function-await 61// AsyncFunctionAwait ( value ) 62// Shared logic for the core of await. The parser desugars 63// await awaited 64// into 65// yield AsyncFunctionAwait{Caught,Uncaught}(.generator, awaited, .promise) 66// The 'awaited' parameter is the value; the generator stands in 67// for the asyncContext, and .promise is the larger promise under 68// construction by the enclosing async function. 69function AsyncFunctionAwait(generator, awaited, outerPromise) { 70 // Promise.resolve(awaited).then( 71 // value => AsyncFunctionNext(value), 72 // error => AsyncFunctionThrow(error) 73 // ); 74 var promise = PromiseCastResolved(awaited); 75 76 var onFulfilled = sentValue => { 77 %_Call(AsyncFunctionNext, generator, sentValue); 78 // The resulting Promise is a throwaway, so it doesn't matter what it 79 // resolves to. What is important is that we don't end up keeping the 80 // whole chain of intermediate Promises alive by returning the value 81 // of AsyncFunctionNext, as that would create a memory leak. 82 return; 83 }; 84 var onRejected = sentError => { 85 %_Call(AsyncFunctionThrow, generator, sentError); 86 // Similarly, returning the huge Promise here would cause a long 87 // resolution chain to find what the exception to throw is, and 88 // create a similar memory leak, and it does not matter what 89 // sort of rejection this intermediate Promise becomes. 90 return; 91 } 92 93 // Just forwarding the exception, so no debugEvent for throwawayCapability 94 var throwawayCapability = NewPromiseCapability(GlobalPromise, false); 95 96 // The Promise will be thrown away and not handled, but it shouldn't trigger 97 // unhandled reject events as its work is done 98 SET_PRIVATE(throwawayCapability.promise, promiseHasHandlerSymbol, true); 99 100 if (DEBUG_IS_ACTIVE) { 101 if (IsPromise(awaited)) { 102 // Mark the reject handler callback to be a forwarding edge, rather 103 // than a meaningful catch handler 104 SET_PRIVATE(onRejected, promiseForwardingHandlerSymbol, true); 105 } 106 107 // Mark the dependency to outerPromise in case the throwaway Promise is 108 // found on the Promise stack 109 SET_PRIVATE(throwawayCapability.promise, promiseHandledBySymbol, 110 outerPromise); 111 } 112 113 PerformPromiseThen(promise, onFulfilled, onRejected, throwawayCapability); 114} 115 116// Called by the parser from the desugaring of 'await' when catch 117// prediction indicates no locally surrounding catch block 118function AsyncFunctionAwaitUncaught(generator, awaited, outerPromise) { 119 AsyncFunctionAwait(generator, awaited, outerPromise); 120} 121 122// Called by the parser from the desugaring of 'await' when catch 123// prediction indicates that there is a locally surrounding catch block 124function AsyncFunctionAwaitCaught(generator, awaited, outerPromise) { 125 if (DEBUG_IS_ACTIVE && IsPromise(awaited)) { 126 SET_PRIVATE(awaited, promiseHandledHintSymbol, true); 127 } 128 AsyncFunctionAwait(generator, awaited, outerPromise); 129} 130 131// How the parser rejects promises from async/await desugaring 132function RejectPromiseNoDebugEvent(promise, reason) { 133 return RejectPromise(promise, reason, false); 134} 135 136function AsyncFunctionPromiseCreate() { 137 var promise = PromiseCreate(); 138 if (DEBUG_IS_ACTIVE) { 139 // Push the Promise under construction in an async function on 140 // the catch prediction stack to handle exceptions thrown before 141 // the first await. 142 %DebugPushPromise(promise); 143 // Assign ID and create a recurring task to save stack for future 144 // resumptions from await. 145 var id = %DebugNextMicrotaskId(); 146 SET_PRIVATE(promise, promiseAsyncStackIDSymbol, id); 147 %DebugAsyncTaskEvent("enqueueRecurring", id, "async function"); 148 } 149 return promise; 150} 151 152function AsyncFunctionPromiseRelease(promise) { 153 if (DEBUG_IS_ACTIVE) { 154 // Cancel 155 var id = GET_PRIVATE(promise, promiseAsyncStackIDSymbol); 156 157 // Don't send invalid events when catch prediction is turned on in 158 // the middle of some async operation. 159 if (!IS_UNDEFINED(id)) { 160 %DebugAsyncTaskEvent("cancel", id, "async function"); 161 } 162 // Pop the Promise under construction in an async function on 163 // from catch prediction stack. 164 %DebugPopPromise(); 165 } 166} 167 168%InstallToContext([ 169 "async_function_await_caught", AsyncFunctionAwaitCaught, 170 "async_function_await_uncaught", AsyncFunctionAwaitUncaught, 171 "reject_promise_no_debug_event", RejectPromiseNoDebugEvent, 172 "async_function_promise_create", AsyncFunctionPromiseCreate, 173 "async_function_promise_release", AsyncFunctionPromiseRelease, 174]); 175 176}) 177