OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 (function(global, utils, extrasUtils) { | 5 (function(global, utils, extrasUtils) { |
6 | 6 |
7 "use strict"; | 7 "use strict"; |
8 | 8 |
9 %CheckIsBootstrapping(); | 9 %CheckIsBootstrapping(); |
10 | 10 |
(...skipping 15 matching lines...) Expand all Loading... |
26 AsyncFunctionThrow = from.AsyncFunctionThrow; | 26 AsyncFunctionThrow = from.AsyncFunctionThrow; |
27 IsPromise = from.IsPromise; | 27 IsPromise = from.IsPromise; |
28 GlobalPromise = from.GlobalPromise; | 28 GlobalPromise = from.GlobalPromise; |
29 NewPromiseCapability = from.NewPromiseCapability; | 29 NewPromiseCapability = from.NewPromiseCapability; |
30 PromiseCreate = from.PromiseCreate; | 30 PromiseCreate = from.PromiseCreate; |
31 PerformPromiseThen = from.PerformPromiseThen; | 31 PerformPromiseThen = from.PerformPromiseThen; |
32 RejectPromise = from.RejectPromise; | 32 RejectPromise = from.RejectPromise; |
33 ResolvePromise = from.ResolvePromise; | 33 ResolvePromise = from.ResolvePromise; |
34 }); | 34 }); |
35 | 35 |
36 var promiseAwaitHandlerSymbol = utils.ImportNow("promise_await_handler_symbol"); | 36 var promiseHandledBySymbol = |
| 37 utils.ImportNow("promise_handled_by_symbol"); |
| 38 var promiseForwardingHandlerSymbol = |
| 39 utils.ImportNow("promise_forwarding_handler_symbol"); |
37 var promiseHandledHintSymbol = | 40 var promiseHandledHintSymbol = |
38 utils.ImportNow("promise_handled_hint_symbol"); | 41 utils.ImportNow("promise_handled_hint_symbol"); |
39 var promiseHasHandlerSymbol = | 42 var promiseHasHandlerSymbol = |
40 utils.ImportNow("promise_has_handler_symbol"); | 43 utils.ImportNow("promise_has_handler_symbol"); |
41 | 44 |
42 // ------------------------------------------------------------------- | 45 // ------------------------------------------------------------------- |
43 | 46 |
44 function PromiseCastResolved(value) { | 47 function PromiseCastResolved(value) { |
45 if (IsPromise(value)) { | 48 if (IsPromise(value)) { |
46 return value; | 49 return value; |
47 } else { | 50 } else { |
48 var promise = PromiseCreate(); | 51 var promise = PromiseCreate(); |
49 ResolvePromise(promise, value); | 52 ResolvePromise(promise, value); |
50 return promise; | 53 return promise; |
51 } | 54 } |
52 } | 55 } |
53 | 56 |
54 // ES#abstract-ops-async-function-await | 57 // ES#abstract-ops-async-function-await |
55 // AsyncFunctionAwait ( value ) | 58 // AsyncFunctionAwait ( value ) |
56 // Shared logic for the core of await. The parser desugars | 59 // Shared logic for the core of await. The parser desugars |
57 // await awaited | 60 // await awaited |
58 // into | 61 // into |
59 // yield AsyncFunctionAwait{Caught,Uncaught}(.generator, awaited) | 62 // yield AsyncFunctionAwait{Caught,Uncaught}(.generator, awaited, .promise) |
60 // The 'awaited' parameter is the value; the generator stands in | 63 // The 'awaited' parameter is the value; the generator stands in |
61 // for the asyncContext, and mark is metadata for debugging | 64 // for the asyncContext, and .promise is the larger promise under |
62 function AsyncFunctionAwait(generator, awaited, mark) { | 65 // construction by the enclosing async function. |
| 66 function AsyncFunctionAwait(generator, awaited, outerPromise) { |
63 // Promise.resolve(awaited).then( | 67 // Promise.resolve(awaited).then( |
64 // value => AsyncFunctionNext(value), | 68 // value => AsyncFunctionNext(value), |
65 // error => AsyncFunctionThrow(error) | 69 // error => AsyncFunctionThrow(error) |
66 // ); | 70 // ); |
67 var promise = PromiseCastResolved(awaited); | 71 var promise = PromiseCastResolved(awaited); |
68 | 72 |
69 var onFulfilled = sentValue => { | 73 var onFulfilled = sentValue => { |
70 %_Call(AsyncFunctionNext, generator, sentValue); | 74 %_Call(AsyncFunctionNext, generator, sentValue); |
71 // The resulting Promise is a throwaway, so it doesn't matter what it | 75 // The resulting Promise is a throwaway, so it doesn't matter what it |
72 // resolves to. What is important is that we don't end up keeping the | 76 // resolves to. What is important is that we don't end up keeping the |
73 // whole chain of intermediate Promises alive by returning the value | 77 // whole chain of intermediate Promises alive by returning the value |
74 // of AsyncFunctionNext, as that would create a memory leak. | 78 // of AsyncFunctionNext, as that would create a memory leak. |
75 return; | 79 return; |
76 }; | 80 }; |
77 var onRejected = sentError => { | 81 var onRejected = sentError => { |
78 %_Call(AsyncFunctionThrow, generator, sentError); | 82 %_Call(AsyncFunctionThrow, generator, sentError); |
79 // Similarly, returning the huge Promise here would cause a long | 83 // Similarly, returning the huge Promise here would cause a long |
80 // resolution chain to find what the exception to throw is, and | 84 // resolution chain to find what the exception to throw is, and |
81 // create a similar memory leak, and it does not matter what | 85 // create a similar memory leak, and it does not matter what |
82 // sort of rejection this intermediate Promise becomes. | 86 // sort of rejection this intermediate Promise becomes. |
83 return; | 87 return; |
84 } | 88 } |
85 | 89 |
86 if (mark && DEBUG_IS_ACTIVE && IsPromise(awaited)) { | |
87 // Mark the reject handler callback such that it does not influence | |
88 // catch prediction. | |
89 SET_PRIVATE(onRejected, promiseAwaitHandlerSymbol, true); | |
90 } | |
91 | |
92 // Just forwarding the exception, so no debugEvent for throwawayCapability | 90 // Just forwarding the exception, so no debugEvent for throwawayCapability |
93 var throwawayCapability = NewPromiseCapability(GlobalPromise, false); | 91 var throwawayCapability = NewPromiseCapability(GlobalPromise, false); |
94 | 92 |
95 // The Promise will be thrown away and not handled, but it shouldn't trigger | 93 // The Promise will be thrown away and not handled, but it shouldn't trigger |
96 // unhandled reject events as its work is done | 94 // unhandled reject events as its work is done |
97 SET_PRIVATE(throwawayCapability.promise, promiseHasHandlerSymbol, true); | 95 SET_PRIVATE(throwawayCapability.promise, promiseHasHandlerSymbol, true); |
98 | 96 |
99 return PerformPromiseThen(promise, onFulfilled, onRejected, | 97 PerformPromiseThen(promise, onFulfilled, onRejected, throwawayCapability); |
100 throwawayCapability); | 98 |
| 99 if (DEBUG_IS_ACTIVE && !IS_UNDEFINED(outerPromise)) { |
| 100 if (IsPromise(awaited)) { |
| 101 // Mark the reject handler callback to be a forwarding edge, rather |
| 102 // than a meaningful catch handler |
| 103 SET_PRIVATE(onRejected, promiseForwardingHandlerSymbol, true); |
| 104 } |
| 105 |
| 106 // Mark the dependency to outerPromise in case the throwaway Promise is |
| 107 // found on the Promise stack |
| 108 SET_PRIVATE(throwawayCapability.promise, promiseHandledBySymbol, |
| 109 outerPromise); |
| 110 } |
101 } | 111 } |
102 | 112 |
103 // Called by the parser from the desugaring of 'await' when catch | 113 // Called by the parser from the desugaring of 'await' when catch |
104 // prediction indicates no locally surrounding catch block | 114 // prediction indicates no locally surrounding catch block |
105 function AsyncFunctionAwaitUncaught(generator, awaited) { | 115 function AsyncFunctionAwaitUncaught(generator, awaited, outerPromise) { |
106 // TODO(littledan): Install a dependency edge from awaited to outerPromise | 116 AsyncFunctionAwait(generator, awaited, outerPromise); |
107 return AsyncFunctionAwait(generator, awaited, true); | |
108 } | 117 } |
109 | 118 |
110 // Called by the parser from the desugaring of 'await' when catch | 119 // Called by the parser from the desugaring of 'await' when catch |
111 // prediction indicates that there is a locally surrounding catch block | 120 // prediction indicates that there is a locally surrounding catch block |
112 function AsyncFunctionAwaitCaught(generator, awaited) { | 121 function AsyncFunctionAwaitCaught(generator, awaited, outerPromise) { |
113 if (DEBUG_IS_ACTIVE && IsPromise(awaited)) { | 122 if (DEBUG_IS_ACTIVE && IsPromise(awaited)) { |
114 SET_PRIVATE(awaited, promiseHandledHintSymbol, true); | 123 SET_PRIVATE(awaited, promiseHandledHintSymbol, true); |
115 } | 124 } |
116 return AsyncFunctionAwait(generator, awaited, false); | 125 // Pass undefined for the outer Promise to not waste time setting up |
| 126 // or following the dependency chain when this Promise is already marked |
| 127 // as handled |
| 128 AsyncFunctionAwait(generator, awaited, UNDEFINED); |
117 } | 129 } |
118 | 130 |
119 // How the parser rejects promises from async/await desugaring | 131 // How the parser rejects promises from async/await desugaring |
120 function RejectPromiseNoDebugEvent(promise, reason) { | 132 function RejectPromiseNoDebugEvent(promise, reason) { |
121 return RejectPromise(promise, reason, false); | 133 return RejectPromise(promise, reason, false); |
122 } | 134 } |
123 | 135 |
124 %InstallToContext([ | 136 %InstallToContext([ |
125 "async_function_await_caught", AsyncFunctionAwaitCaught, | 137 "async_function_await_caught", AsyncFunctionAwaitCaught, |
126 "async_function_await_uncaught", AsyncFunctionAwaitUncaught, | 138 "async_function_await_uncaught", AsyncFunctionAwaitUncaught, |
127 "reject_promise_no_debug_event", RejectPromiseNoDebugEvent, | 139 "reject_promise_no_debug_event", RejectPromiseNoDebugEvent, |
128 ]); | 140 ]); |
129 | 141 |
130 }) | 142 }) |
OLD | NEW |