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 |