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