OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 |
11 // ------------------------------------------------------------------- | 11 // ------------------------------------------------------------------- |
12 // Imports | 12 // Imports |
13 | 13 |
14 var InternalArray = utils.InternalArray; | 14 var InternalArray = utils.InternalArray; |
15 var promiseAsyncStackIDSymbol = | 15 var promiseAsyncStackIDSymbol = |
16 utils.ImportNow("promise_async_stack_id_symbol"); | 16 utils.ImportNow("promise_async_stack_id_symbol"); |
17 var promiseHandledBySymbol = | 17 var promiseHandledBySymbol = |
18 utils.ImportNow("promise_handled_by_symbol"); | 18 utils.ImportNow("promise_handled_by_symbol"); |
19 var promiseForwardingHandlerSymbol = | 19 var promiseForwardingHandlerSymbol = |
20 utils.ImportNow("promise_forwarding_handler_symbol"); | 20 utils.ImportNow("promise_forwarding_handler_symbol"); |
21 var promiseHasHandlerSymbol = | 21 var promiseHasHandlerSymbol = |
22 utils.ImportNow("promise_has_handler_symbol"); | 22 utils.ImportNow("promise_has_handler_symbol"); |
| 23 var promiseRejectReactionsSymbol = |
| 24 utils.ImportNow("promise_reject_reactions_symbol"); |
| 25 var promiseFulfillReactionsSymbol = |
| 26 utils.ImportNow("promise_fulfill_reactions_symbol"); |
| 27 var promiseDeferredReactionSymbol = |
| 28 utils.ImportNow("promise_deferred_reaction_symbol"); |
23 var promiseHandledHintSymbol = | 29 var promiseHandledHintSymbol = |
24 utils.ImportNow("promise_handled_hint_symbol"); | 30 utils.ImportNow("promise_handled_hint_symbol"); |
25 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); | 31 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); |
26 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); | 32 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); |
27 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); | 33 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); |
28 var SpeciesConstructor; | 34 var SpeciesConstructor; |
29 var speciesSymbol = utils.ImportNow("species_symbol"); | 35 var speciesSymbol = utils.ImportNow("species_symbol"); |
30 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); | 36 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); |
31 var ObjectHasOwnProperty; | 37 var ObjectHasOwnProperty; |
32 var GlobalPromise = global.Promise; | 38 var GlobalPromise = global.Promise; |
33 var PromiseThen = GlobalPromise.prototype.then; | |
34 | 39 |
35 utils.Import(function(from) { | 40 utils.Import(function(from) { |
36 ObjectHasOwnProperty = from.ObjectHasOwnProperty; | 41 ObjectHasOwnProperty = from.ObjectHasOwnProperty; |
37 SpeciesConstructor = from.SpeciesConstructor; | 42 SpeciesConstructor = from.SpeciesConstructor; |
38 }); | 43 }); |
39 | 44 |
40 // ------------------------------------------------------------------- | 45 // ------------------------------------------------------------------- |
41 | 46 |
42 // Core functionality. | 47 // Core functionality. |
43 | 48 |
| 49 function PromiseSet(promise, status, value) { |
| 50 SET_PRIVATE(promise, promiseStateSymbol, status); |
| 51 SET_PRIVATE(promise, promiseResultSymbol, value); |
| 52 |
| 53 // There are 3 possible states for the resolve, reject symbols when we add |
| 54 // a new callback -- |
| 55 // 1) UNDEFINED -- This is the zero state where there is no callback |
| 56 // registered. When we see this state, we directly attach the callbacks to |
| 57 // the symbol. |
| 58 // 2) !IS_ARRAY -- There is a single callback directly attached to the |
| 59 // symbols. We need to create a new array to store additional callbacks. |
| 60 // 3) IS_ARRAY -- There are multiple callbacks already registered, |
| 61 // therefore we can just push the new callback to the existing array. |
| 62 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, UNDEFINED); |
| 63 SET_PRIVATE(promise, promiseRejectReactionsSymbol, UNDEFINED); |
| 64 |
| 65 // This symbol is used only when one deferred needs to be attached. When more |
| 66 // than one deferred need to be attached the promise, we attach them directly |
| 67 // to the promiseFulfillReactionsSymbol and promiseRejectReactionsSymbol and |
| 68 // reset this back to UNDEFINED. |
| 69 SET_PRIVATE(promise, promiseDeferredReactionSymbol, UNDEFINED); |
| 70 |
| 71 return promise; |
| 72 } |
| 73 |
| 74 function PromiseCreateAndSet(status, value) { |
| 75 var promise = %promise_internal_constructor(); |
| 76 // If debug is active, notify about the newly created promise first. |
| 77 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED); |
| 78 return PromiseSet(promise, status, value); |
| 79 } |
| 80 |
| 81 function PromiseInit(promise) { |
| 82 return PromiseSet(promise, kPending, UNDEFINED); |
| 83 } |
| 84 |
44 function PromiseHandle(value, handler, deferred) { | 85 function PromiseHandle(value, handler, deferred) { |
45 var debug_is_active = DEBUG_IS_ACTIVE; | 86 var debug_is_active = DEBUG_IS_ACTIVE; |
46 try { | 87 try { |
47 if (debug_is_active) %DebugPushPromise(deferred.promise); | 88 if (debug_is_active) %DebugPushPromise(deferred.promise); |
48 var result = handler(value); | 89 var result = handler(value); |
49 if (IS_UNDEFINED(deferred.resolve)) { | 90 if (IS_UNDEFINED(deferred.resolve)) { |
50 ResolvePromise(deferred.promise, result); | 91 ResolvePromise(deferred.promise, result); |
51 } else { | 92 } else { |
52 %_Call(deferred.resolve, UNDEFINED, result); | 93 %_Call(deferred.resolve, UNDEFINED, result); |
53 } | 94 } |
54 } %catch (exception) { // Natives syntax to mark this catch block. | 95 } %catch (exception) { // Natives syntax to mark this catch block. |
55 try { | 96 try { |
56 if (IS_UNDEFINED(deferred.reject)) { | 97 if (IS_UNDEFINED(deferred.reject)) { |
57 // Pass false for debugEvent so .then chaining or throwaway promises | 98 // Pass false for debugEvent so .then chaining or throwaway promises |
58 // in async functions do not trigger redundant ExceptionEvents. | 99 // in async functions do not trigger redundant ExceptionEvents. |
59 %PromiseReject(deferred.promise, exception, false); | 100 %PromiseReject(deferred.promise, exception, false); |
| 101 PromiseSet(deferred.promise, kRejected, exception); |
60 } else { | 102 } else { |
61 %_Call(deferred.reject, UNDEFINED, exception); | 103 %_Call(deferred.reject, UNDEFINED, exception); |
62 } | 104 } |
63 } catch (e) { } | 105 } catch (e) { } |
64 } finally { | 106 } finally { |
65 if (debug_is_active) %DebugPopPromise(); | 107 if (debug_is_active) %DebugPopPromise(); |
66 } | 108 } |
67 } | 109 } |
68 | 110 |
69 function PromiseDebugGetInfo(deferreds, status) { | 111 function PromiseDebugGetInfo(deferreds, status) { |
(...skipping 15 matching lines...) Expand all Loading... |
85 name = "async function"; | 127 name = "async function"; |
86 } else { | 128 } else { |
87 id = %DebugNextMicrotaskId(); | 129 id = %DebugNextMicrotaskId(); |
88 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject"; | 130 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject"; |
89 %DebugAsyncTaskEvent("enqueue", id, name); | 131 %DebugAsyncTaskEvent("enqueue", id, name); |
90 } | 132 } |
91 } | 133 } |
92 return [id, name]; | 134 return [id, name]; |
93 } | 135 } |
94 | 136 |
| 137 function PromiseAttachCallbacks(promise, deferred, onResolve, onReject) { |
| 138 var maybeResolveCallbacks = |
| 139 GET_PRIVATE(promise, promiseFulfillReactionsSymbol); |
| 140 if (IS_UNDEFINED(maybeResolveCallbacks)) { |
| 141 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve); |
| 142 SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject); |
| 143 SET_PRIVATE(promise, promiseDeferredReactionSymbol, deferred); |
| 144 } else if (!IS_ARRAY(maybeResolveCallbacks)) { |
| 145 var resolveCallbacks = new InternalArray(); |
| 146 var rejectCallbacks = new InternalArray(); |
| 147 var existingDeferred = GET_PRIVATE(promise, promiseDeferredReactionSymbol); |
| 148 |
| 149 resolveCallbacks.push( |
| 150 maybeResolveCallbacks, existingDeferred, onResolve, deferred); |
| 151 rejectCallbacks.push(GET_PRIVATE(promise, promiseRejectReactionsSymbol), |
| 152 existingDeferred, |
| 153 onReject, |
| 154 deferred); |
| 155 |
| 156 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks); |
| 157 SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks); |
| 158 SET_PRIVATE(promise, promiseDeferredReactionSymbol, UNDEFINED); |
| 159 } else { |
| 160 maybeResolveCallbacks.push(onResolve, deferred); |
| 161 GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject, deferred); |
| 162 } |
| 163 } |
| 164 |
95 function PromiseIdResolveHandler(x) { return x; } | 165 function PromiseIdResolveHandler(x) { return x; } |
96 function PromiseIdRejectHandler(r) { %_ReThrow(r); } | 166 function PromiseIdRejectHandler(r) { %_ReThrow(r); } |
97 SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true); | 167 SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true); |
98 | 168 |
99 // ------------------------------------------------------------------- | 169 // ------------------------------------------------------------------- |
100 // Define exported functions. | 170 // Define exported functions. |
101 | 171 |
102 // For bootstrapper. | 172 // For bootstrapper. |
103 | 173 |
104 // This is used by utils and v8-extras. | |
105 function PromiseCreate() { | 174 function PromiseCreate() { |
106 return %promise_internal_constructor(); | 175 return PromiseInit(%promise_internal_constructor()); |
107 } | 176 } |
108 | 177 |
109 // ES#sec-promise-resolve-functions | 178 // ES#sec-promise-resolve-functions |
110 // Promise Resolve Functions, steps 6-13 | 179 // Promise Resolve Functions, steps 6-13 |
111 function ResolvePromise(promise, resolution) { | 180 function ResolvePromise(promise, resolution) { |
112 if (resolution === promise) { | 181 if (resolution === promise) { |
113 var exception = %make_type_error(kPromiseCyclic, resolution); | 182 var exception = %make_type_error(kPromiseCyclic, resolution); |
114 %PromiseReject(promise, exception, true); | 183 %PromiseReject(promise, exception, true); |
| 184 PromiseSet(promise, kRejected, exception); |
115 return; | 185 return; |
116 } | 186 } |
117 if (IS_RECEIVER(resolution)) { | 187 if (IS_RECEIVER(resolution)) { |
118 // 25.4.1.3.2 steps 8-12 | 188 // 25.4.1.3.2 steps 8-12 |
119 try { | 189 try { |
120 var then = resolution.then; | 190 var then = resolution.then; |
121 } catch (e) { | 191 } catch (e) { |
122 %PromiseReject(promise, e, true); | 192 %PromiseReject(promise, e, true); |
| 193 PromiseSet(promise, kRejected, e); |
123 return; | 194 return; |
124 } | 195 } |
125 | 196 |
126 // Resolution is a native promise and if it's already resolved or | 197 // Resolution is a native promise and if it's already resolved or |
127 // rejected, shortcircuit the resolution procedure by directly | 198 // rejected, shortcircuit the resolution procedure by directly |
128 // reusing the value from the promise. | 199 // reusing the value from the promise. |
129 if (%is_promise(resolution) && then === PromiseThen) { | 200 if (%is_promise(resolution) && then === PromiseThen) { |
130 var thenableState = %PromiseStatus(resolution); | 201 var thenableState = GET_PRIVATE(resolution, promiseStateSymbol); |
131 if (thenableState === kFulfilled) { | 202 if (thenableState === kFulfilled) { |
132 // This goes inside the if-else to save one symbol lookup in | 203 // This goes inside the if-else to save one symbol lookup in |
133 // the slow path. | 204 // the slow path. |
134 var thenableValue = %PromiseResult(resolution); | 205 var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol); |
135 %PromiseFulfill(promise, kFulfilled, thenableValue); | 206 %PromiseFulfill(promise, kFulfilled, thenableValue, |
| 207 promiseFulfillReactionsSymbol); |
| 208 PromiseSet(promise, kFulfilled, thenableValue); |
136 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); | 209 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); |
137 return; | 210 return; |
138 } else if (thenableState === kRejected) { | 211 } else if (thenableState === kRejected) { |
139 var thenableValue = %PromiseResult(resolution); | 212 var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol); |
140 if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) { | 213 if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) { |
141 // Promise has already been rejected, but had no handler. | 214 // Promise has already been rejected, but had no handler. |
142 // Revoke previously triggered reject event. | 215 // Revoke previously triggered reject event. |
143 %PromiseRevokeReject(resolution); | 216 %PromiseRevokeReject(resolution); |
144 } | 217 } |
145 // Don't cause a debug event as this case is forwarding a rejection | 218 // Don't cause a debug event as this case is forwarding a rejection |
146 %PromiseReject(promise, thenableValue, false); | 219 %PromiseReject(promise, thenableValue, false); |
| 220 PromiseSet(promise, kRejected, thenableValue); |
147 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); | 221 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); |
148 return; | 222 return; |
149 } | 223 } |
150 } | 224 } |
151 | 225 |
152 if (IS_CALLABLE(then)) { | 226 if (IS_CALLABLE(then)) { |
153 if (DEBUG_IS_ACTIVE && %is_promise(resolution)) { | 227 if (DEBUG_IS_ACTIVE && %is_promise(resolution)) { |
154 // Mark the dependency of the new promise on the resolution | 228 // Mark the dependency of the new promise on the resolution |
155 SET_PRIVATE(resolution, promiseHandledBySymbol, promise); | 229 SET_PRIVATE(resolution, promiseHandledBySymbol, promise); |
156 } | 230 } |
157 %EnqueuePromiseResolveThenableJob(promise, resolution, then); | 231 %EnqueuePromiseResolveThenableJob(promise, resolution, then); |
158 return; | 232 return; |
159 } | 233 } |
160 } | 234 } |
161 %PromiseFulfill(promise, kFulfilled, resolution); | 235 %PromiseFulfill(promise, kFulfilled, resolution, |
| 236 promiseFulfillReactionsSymbol); |
| 237 PromiseSet(promise, kFulfilled, resolution); |
162 } | 238 } |
163 | 239 |
164 // Only used by async-await.js | 240 // Only used by async-await.js |
165 function RejectPromise(promise, reason, debugEvent) { | 241 function RejectPromise(promise, reason, debugEvent) { |
166 %PromiseReject(promise, reason, debugEvent); | 242 %PromiseReject(promise, reason, debugEvent); |
| 243 PromiseSet(promise, kRejected, reason); |
167 } | 244 } |
168 | 245 |
169 // Export to bindings | 246 // Export to bindings |
170 function DoRejectPromise(promise, reason) { | 247 function DoRejectPromise(promise, reason) { |
171 %PromiseReject(promise, reason, true); | 248 %PromiseReject(promise, reason, true); |
| 249 PromiseSet(promise, kRejected, reason); |
172 } | 250 } |
173 | 251 |
174 // The resultCapability.promise is only ever fulfilled internally, | 252 // The resultCapability.promise is only ever fulfilled internally, |
175 // so we don't need the closures to protect against accidentally | 253 // so we don't need the closures to protect against accidentally |
176 // calling them multiple times. | 254 // calling them multiple times. |
177 function CreateInternalPromiseCapability() { | 255 function CreateInternalPromiseCapability() { |
178 return { | 256 return { |
179 promise: %promise_internal_constructor(), | 257 promise: PromiseCreate(), |
180 resolve: UNDEFINED, | 258 resolve: UNDEFINED, |
181 reject: UNDEFINED | 259 reject: UNDEFINED |
182 }; | 260 }; |
183 } | 261 } |
184 | 262 |
185 // ES#sec-newpromisecapability | 263 // ES#sec-newpromisecapability |
186 // NewPromiseCapability ( C ) | 264 // NewPromiseCapability ( C ) |
187 function NewPromiseCapability(C, debugEvent) { | 265 function NewPromiseCapability(C, debugEvent) { |
188 if (C === GlobalPromise) { | 266 if (C === GlobalPromise) { |
189 // Optimized case, avoid extra closure. | 267 // Optimized case, avoid extra closure. |
190 var promise = %promise_internal_constructor(); | 268 var promise = PromiseCreate(); |
191 // TODO(gsathya): Remove container for callbacks when this is | 269 // TODO(gsathya): Remove container for callbacks when this is |
192 // moved to CPP/TF. | 270 // moved to CPP/TF. |
193 var callbacks = %create_resolving_functions(promise, debugEvent); | 271 var callbacks = %create_resolving_functions(promise, debugEvent); |
194 return { | 272 return { |
195 promise: promise, | 273 promise: promise, |
196 resolve: callbacks[kResolveCallback], | 274 resolve: callbacks[kResolveCallback], |
197 reject: callbacks[kRejectCallback] | 275 reject: callbacks[kRejectCallback] |
198 }; | 276 }; |
199 } | 277 } |
200 | 278 |
(...skipping 12 matching lines...) Expand all Loading... |
213 } | 291 } |
214 | 292 |
215 // ES#sec-promise.reject | 293 // ES#sec-promise.reject |
216 // Promise.reject ( x ) | 294 // Promise.reject ( x ) |
217 function PromiseReject(r) { | 295 function PromiseReject(r) { |
218 if (!IS_RECEIVER(this)) { | 296 if (!IS_RECEIVER(this)) { |
219 throw %make_type_error(kCalledOnNonObject, PromiseResolve); | 297 throw %make_type_error(kCalledOnNonObject, PromiseResolve); |
220 } | 298 } |
221 if (this === GlobalPromise) { | 299 if (this === GlobalPromise) { |
222 // Optimized case, avoid extra closure. | 300 // Optimized case, avoid extra closure. |
223 var promise = %promise_create_and_set(kRejected, r); | 301 var promise = PromiseCreateAndSet(kRejected, r); |
224 // Trigger debug events if the debugger is on, as Promise.reject is | 302 // Trigger debug events if the debugger is on, as Promise.reject is |
225 // equivalent to throwing an exception directly. | 303 // equivalent to throwing an exception directly. |
226 %PromiseRejectEventFromStack(promise, r); | 304 %PromiseRejectEventFromStack(promise, r); |
227 return promise; | 305 return promise; |
228 } else { | 306 } else { |
229 var promiseCapability = NewPromiseCapability(this, true); | 307 var promiseCapability = NewPromiseCapability(this, true); |
230 %_Call(promiseCapability.reject, UNDEFINED, r); | 308 %_Call(promiseCapability.reject, UNDEFINED, r); |
231 return promiseCapability.promise; | 309 return promiseCapability.promise; |
232 } | 310 } |
233 } | 311 } |
234 | 312 |
| 313 function PerformPromiseThen(promise, onResolve, onReject, resultCapability) { |
| 314 if (!IS_CALLABLE(onResolve)) onResolve = PromiseIdResolveHandler; |
| 315 if (!IS_CALLABLE(onReject)) onReject = PromiseIdRejectHandler; |
| 316 |
| 317 var status = GET_PRIVATE(promise, promiseStateSymbol); |
| 318 switch (status) { |
| 319 case kPending: |
| 320 PromiseAttachCallbacks(promise, resultCapability, onResolve, onReject); |
| 321 break; |
| 322 case kFulfilled: |
| 323 %EnqueuePromiseReactionJob(GET_PRIVATE(promise, promiseResultSymbol), |
| 324 onResolve, resultCapability, kFulfilled); |
| 325 break; |
| 326 case kRejected: |
| 327 if (!HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { |
| 328 // Promise has already been rejected, but had no handler. |
| 329 // Revoke previously triggered reject event. |
| 330 %PromiseRevokeReject(promise); |
| 331 } |
| 332 %EnqueuePromiseReactionJob(GET_PRIVATE(promise, promiseResultSymbol), |
| 333 onReject, resultCapability, kRejected); |
| 334 break; |
| 335 } |
| 336 |
| 337 // Mark this promise as having handler. |
| 338 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); |
| 339 return resultCapability.promise; |
| 340 } |
| 341 |
| 342 // ES#sec-promise.prototype.then |
| 343 // Promise.prototype.then ( onFulfilled, onRejected ) |
| 344 // Multi-unwrapped chaining with thenable coercion. |
| 345 function PromiseThen(onResolve, onReject) { |
| 346 if (!%is_promise(this)) { |
| 347 throw %make_type_error(kNotAPromise, this); |
| 348 } |
| 349 |
| 350 var constructor = SpeciesConstructor(this, GlobalPromise); |
| 351 var resultCapability; |
| 352 if (constructor === GlobalPromise) { |
| 353 resultCapability = CreateInternalPromiseCapability(); |
| 354 } else { |
| 355 // Pass false for debugEvent so .then chaining does not trigger |
| 356 // redundant ExceptionEvents. |
| 357 resultCapability = NewPromiseCapability(constructor, false); |
| 358 } |
| 359 return PerformPromiseThen(this, onResolve, onReject, resultCapability); |
| 360 } |
| 361 |
235 // ES#sec-promise.prototype.catch | 362 // ES#sec-promise.prototype.catch |
236 // Promise.prototype.catch ( onRejected ) | 363 // Promise.prototype.catch ( onRejected ) |
237 function PromiseCatch(onReject) { | 364 function PromiseCatch(onReject) { |
238 return this.then(UNDEFINED, onReject); | 365 return this.then(UNDEFINED, onReject); |
239 } | 366 } |
240 | 367 |
241 // Combinators. | 368 // Combinators. |
242 | 369 |
243 // ES#sec-promise.resolve | 370 // ES#sec-promise.resolve |
244 // Promise.resolve ( x ) | 371 // Promise.resolve ( x ) |
245 function PromiseResolve(x) { | 372 function PromiseResolve(x) { |
246 if (!IS_RECEIVER(this)) { | 373 if (!IS_RECEIVER(this)) { |
247 throw %make_type_error(kCalledOnNonObject, PromiseResolve); | 374 throw %make_type_error(kCalledOnNonObject, PromiseResolve); |
248 } | 375 } |
249 if (%is_promise(x) && x.constructor === this) return x; | 376 if (%is_promise(x) && x.constructor === this) return x; |
250 | 377 |
251 // Avoid creating resolving functions. | 378 // Avoid creating resolving functions. |
252 if (this === GlobalPromise) { | 379 if (this === GlobalPromise) { |
253 var promise = %promise_internal_constructor(); | 380 var promise = PromiseCreate(); |
254 ResolvePromise(promise, x); | 381 ResolvePromise(promise, x); |
255 return promise; | 382 return promise; |
256 } | 383 } |
257 | 384 |
258 // debugEvent is not so meaningful here as it will be resolved | 385 // debugEvent is not so meaningful here as it will be resolved |
259 var promiseCapability = NewPromiseCapability(this, true); | 386 var promiseCapability = NewPromiseCapability(this, true); |
260 %_Call(promiseCapability.resolve, UNDEFINED, x); | 387 %_Call(promiseCapability.resolve, UNDEFINED, x); |
261 return promiseCapability.promise; | 388 return promiseCapability.promise; |
262 } | 389 } |
263 | 390 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 // with another Promise, or an intermediate, hidden, throwaway Promise | 513 // with another Promise, or an intermediate, hidden, throwaway Promise |
387 // within async/await), then recurse on the outer Promise. | 514 // within async/await), then recurse on the outer Promise. |
388 // In this case, the dependency is one possible way that the Promise | 515 // In this case, the dependency is one possible way that the Promise |
389 // could be resolved, so it does not subsume the other following cases. | 516 // could be resolved, so it does not subsume the other following cases. |
390 var outerPromise = GET_PRIVATE(promise, promiseHandledBySymbol); | 517 var outerPromise = GET_PRIVATE(promise, promiseHandledBySymbol); |
391 if (outerPromise && | 518 if (outerPromise && |
392 PromiseHasUserDefinedRejectHandlerRecursive(outerPromise)) { | 519 PromiseHasUserDefinedRejectHandlerRecursive(outerPromise)) { |
393 return true; | 520 return true; |
394 } | 521 } |
395 | 522 |
396 if (!%is_promise(promise)) return false; | 523 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol); |
397 | 524 var deferred = GET_PRIVATE(promise, promiseDeferredReactionSymbol); |
398 var queue = %PromiseRejectReactions(promise); | |
399 var deferred = %PromiseDeferred(promise); | |
400 | 525 |
401 if (IS_UNDEFINED(queue)) return false; | 526 if (IS_UNDEFINED(queue)) return false; |
402 | 527 |
403 if (!IS_ARRAY(queue)) { | 528 if (!IS_ARRAY(queue)) { |
404 return PromiseHasUserDefinedRejectHandlerCheck(queue, deferred); | 529 return PromiseHasUserDefinedRejectHandlerCheck(queue, deferred); |
405 } | 530 } |
406 | 531 |
407 for (var i = 0; i < queue.length; i++) { | 532 for (var i = 0; i < queue.length; i += 2) { |
408 if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], deferred[i])) { | 533 if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], queue[i + 1])) { |
409 return true; | 534 return true; |
410 } | 535 } |
411 } | 536 } |
412 return false; | 537 return false; |
413 } | 538 } |
414 | 539 |
415 // Return whether the promise will be handled by a user-defined reject | 540 // Return whether the promise will be handled by a user-defined reject |
416 // handler somewhere down the promise chain. For this, we do a depth-first | 541 // handler somewhere down the promise chain. For this, we do a depth-first |
417 // search for a reject handler that's not the default PromiseIdRejectHandler. | 542 // search for a reject handler that's not the default PromiseIdRejectHandler. |
418 // This function also traverses dependencies of one Promise on another, | 543 // This function also traverses dependencies of one Promise on another, |
(...skipping 17 matching lines...) Expand all Loading... |
436 utils.InstallFunctions(GlobalPromise, DONT_ENUM, [ | 561 utils.InstallFunctions(GlobalPromise, DONT_ENUM, [ |
437 "reject", PromiseReject, | 562 "reject", PromiseReject, |
438 "all", PromiseAll, | 563 "all", PromiseAll, |
439 "race", PromiseRace, | 564 "race", PromiseRace, |
440 "resolve", PromiseResolve | 565 "resolve", PromiseResolve |
441 ]); | 566 ]); |
442 | 567 |
443 utils.InstallGetter(GlobalPromise, speciesSymbol, PromiseSpecies); | 568 utils.InstallGetter(GlobalPromise, speciesSymbol, PromiseSpecies); |
444 | 569 |
445 utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [ | 570 utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [ |
| 571 "then", PromiseThen, |
446 "catch", PromiseCatch | 572 "catch", PromiseCatch |
447 ]); | 573 ]); |
448 | 574 |
449 %InstallToContext([ | 575 %InstallToContext([ |
450 "promise_catch", PromiseCatch, | 576 "promise_catch", PromiseCatch, |
451 "promise_create", PromiseCreate, | 577 "promise_create", PromiseCreate, |
452 "promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler, | 578 "promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler, |
453 "promise_reject", DoRejectPromise, | 579 "promise_reject", DoRejectPromise, |
454 // TODO(gsathya): Remove this once we update the promise builtin. | 580 // TODO(gsathya): Remove this once we update the promise builtin. |
455 "promise_internal_reject", RejectPromise, | 581 "promise_internal_reject", RejectPromise, |
456 "promise_resolve", ResolvePromise, | 582 "promise_resolve", ResolvePromise, |
457 "promise_then", PromiseThen, | 583 "promise_then", PromiseThen, |
458 "promise_handle", PromiseHandle, | 584 "promise_handle", PromiseHandle, |
459 "promise_debug_get_info", PromiseDebugGetInfo, | 585 "promise_debug_get_info", PromiseDebugGetInfo |
460 "new_promise_capability", NewPromiseCapability, | |
461 "internal_promise_capability", CreateInternalPromiseCapability, | |
462 "promise_id_resolve_handler", PromiseIdResolveHandler, | |
463 "promise_id_reject_handler", PromiseIdRejectHandler | |
464 ]); | 586 ]); |
465 | 587 |
466 // This allows extras to create promises quickly without building extra | 588 // This allows extras to create promises quickly without building extra |
467 // resolve/reject closures, and allows them to later resolve and reject any | 589 // resolve/reject closures, and allows them to later resolve and reject any |
468 // promise without having to hold on to those closures forever. | 590 // promise without having to hold on to those closures forever. |
469 utils.InstallFunctions(extrasUtils, 0, [ | 591 utils.InstallFunctions(extrasUtils, 0, [ |
470 "createPromise", PromiseCreate, | 592 "createPromise", PromiseCreate, |
471 "resolvePromise", ResolvePromise, | 593 "resolvePromise", ResolvePromise, |
472 "rejectPromise", DoRejectPromise, | 594 "rejectPromise", DoRejectPromise, |
473 "markPromiseAsHandled", MarkPromiseAsHandled | 595 "markPromiseAsHandled", MarkPromiseAsHandled |
474 ]); | 596 ]); |
475 | 597 |
476 utils.Export(function(to) { | 598 utils.Export(function(to) { |
477 to.PromiseCreate = PromiseCreate; | 599 to.PromiseCreate = PromiseCreate; |
478 to.PromiseThen = PromiseThen; | 600 to.PromiseThen = PromiseThen; |
479 | 601 |
480 to.CreateInternalPromiseCapability = CreateInternalPromiseCapability; | 602 to.CreateInternalPromiseCapability = CreateInternalPromiseCapability; |
| 603 to.PerformPromiseThen = PerformPromiseThen; |
481 to.ResolvePromise = ResolvePromise; | 604 to.ResolvePromise = ResolvePromise; |
482 to.RejectPromise = RejectPromise; | 605 to.RejectPromise = RejectPromise; |
483 }); | 606 }); |
484 | 607 |
485 }) | 608 }) |
OLD | NEW |