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 MakeTypeError; | 15 var MakeTypeError; |
16 var promiseCombinedDeferredSymbol = | 16 var promiseCombinedDeferredSymbol = |
17 utils.ImportNow("promise_combined_deferred_symbol"); | 17 utils.ImportNow("promise_combined_deferred_symbol"); |
18 var promiseHasHandlerSymbol = | 18 var promiseHasHandlerSymbol = |
19 utils.ImportNow("promise_has_handler_symbol"); | 19 utils.ImportNow("promise_has_handler_symbol"); |
20 var promiseRejectReactionsSymbol = | 20 var promiseRejectReactionsSymbol = |
21 utils.ImportNow("promise_reject_reactions_symbol"); | 21 utils.ImportNow("promise_reject_reactions_symbol"); |
22 var promiseFulfillReactionsSymbol = | 22 var promiseFulfillReactionsSymbol = |
23 utils.ImportNow("promise_fulfill_reactions_symbol"); | 23 utils.ImportNow("promise_fulfill_reactions_symbol"); |
24 var promiseDeferredReactionsSymbol = | |
25 utils.ImportNow("promise_deferred_reactions_symbol"); | |
24 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); | 26 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); |
25 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); | 27 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); |
26 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); | 28 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); |
27 var SpeciesConstructor; | 29 var SpeciesConstructor; |
28 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); | 30 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); |
29 | 31 |
30 utils.Import(function(from) { | 32 utils.Import(function(from) { |
31 MakeTypeError = from.MakeTypeError; | 33 MakeTypeError = from.MakeTypeError; |
32 SpeciesConstructor = from.SpeciesConstructor; | 34 SpeciesConstructor = from.SpeciesConstructor; |
33 }); | 35 }); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 %_Call(callbacks.reject, UNDEFINED, e); | 93 %_Call(callbacks.reject, UNDEFINED, e); |
92 } finally { | 94 } finally { |
93 if (debug_is_active) %DebugPopPromise(); | 95 if (debug_is_active) %DebugPopPromise(); |
94 } | 96 } |
95 | 97 |
96 return promise; | 98 return promise; |
97 } | 99 } |
98 | 100 |
99 // Core functionality. | 101 // Core functionality. |
100 | 102 |
101 function PromiseSet(promise, status, value, onResolve, onReject) { | 103 function PromiseSet( |
104 promise, status, value, onResolve, onReject, deferred) { | |
adamk
2016/05/25 19:18:57
None of the callers pass more than 3 arguments any
gsathya
2016/05/25 21:46:35
Done.
| |
102 SET_PRIVATE(promise, promiseStateSymbol, status); | 105 SET_PRIVATE(promise, promiseStateSymbol, status); |
103 SET_PRIVATE(promise, promiseResultSymbol, value); | 106 SET_PRIVATE(promise, promiseResultSymbol, value); |
104 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve); | 107 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve); |
adamk
2016/05/25 19:18:57
Maybe add a comment here with a version of the thi
gsathya
2016/05/25 21:46:35
Done. Let me know if you can think of a more cohes
| |
105 SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject); | 108 SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject); |
109 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, deferred); | |
106 return promise; | 110 return promise; |
107 } | 111 } |
108 | 112 |
109 function PromiseCreateAndSet(status, value) { | 113 function PromiseCreateAndSet(status, value) { |
110 var promise = new GlobalPromise(promiseRawSymbol); | 114 var promise = new GlobalPromise(promiseRawSymbol); |
111 // If debug is active, notify about the newly created promise first. | 115 // If debug is active, notify about the newly created promise first. |
112 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED); | 116 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED); |
113 return PromiseSet(promise, status, value); | 117 return PromiseSet(promise, status, value); |
114 } | 118 } |
115 | 119 |
116 function PromiseInit(promise) { | 120 function PromiseInit(promise) { |
117 return PromiseSet( | 121 return PromiseSet( |
118 promise, kPending, UNDEFINED, new InternalArray, new InternalArray) | 122 promise, kPending, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED); |
119 } | 123 } |
120 | 124 |
121 function PromiseDone(promise, status, value, promiseQueue) { | 125 function PromiseDone(promise, status, value, promiseQueue) { |
122 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { | 126 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { |
123 var tasks = GET_PRIVATE(promise, promiseQueue); | 127 var tasks = GET_PRIVATE(promise, promiseQueue); |
124 if (tasks.length) PromiseEnqueue(value, tasks, status); | 128 if (!IS_NULL_OR_UNDEFINED(tasks)) { |
adamk
2016/05/25 19:18:57
It should never be null, right? Can this just be I
gsathya
2016/05/25 21:46:35
Done.
| |
129 var tasks = GET_PRIVATE(promise, promiseQueue); | |
130 var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol); | |
131 PromiseEnqueue(value, tasks, deferreds, status); | |
132 } | |
125 PromiseSet(promise, status, value); | 133 PromiseSet(promise, status, value); |
126 } | 134 } |
127 } | 135 } |
128 | 136 |
129 function PromiseHandle(value, handler, deferred) { | 137 function PromiseHandle(value, handler, deferred) { |
130 var debug_is_active = DEBUG_IS_ACTIVE; | 138 var debug_is_active = DEBUG_IS_ACTIVE; |
131 try { | 139 try { |
132 if (debug_is_active) %DebugPushPromise(deferred.promise, PromiseHandle); | 140 if (debug_is_active) %DebugPushPromise(deferred.promise, PromiseHandle); |
133 var result = handler(value); | 141 var result = handler(value); |
134 deferred.resolve(result); | 142 deferred.resolve(result); |
135 } catch (exception) { | 143 } catch (exception) { |
136 try { deferred.reject(exception); } catch (e) { } | 144 try { deferred.reject(exception); } catch (e) { } |
137 } finally { | 145 } finally { |
138 if (debug_is_active) %DebugPopPromise(); | 146 if (debug_is_active) %DebugPopPromise(); |
139 } | 147 } |
140 } | 148 } |
141 | 149 |
142 function PromiseEnqueue(value, tasks, status) { | 150 function PromiseEnqueue(value, tasks, deferreds, status) { |
143 var id, name, instrumenting = DEBUG_IS_ACTIVE; | 151 var id, name, instrumenting = DEBUG_IS_ACTIVE; |
144 %EnqueueMicrotask(function() { | 152 %EnqueueMicrotask(function() { |
145 if (instrumenting) { | 153 if (instrumenting) { |
146 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); | 154 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); |
147 } | 155 } |
148 for (var i = 0; i < tasks.length; i += 2) { | 156 if (IS_ARRAY(tasks)) { |
149 PromiseHandle(value, tasks[i], tasks[i + 1]) | 157 for (var i = 0; i < tasks.length; i += 1) { |
158 PromiseHandle(value, tasks[i], deferreds[i]); | |
159 } | |
160 } else { | |
161 PromiseHandle(value, tasks, deferreds); | |
150 } | 162 } |
151 if (instrumenting) { | 163 if (instrumenting) { |
152 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); | 164 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); |
153 } | 165 } |
154 }); | 166 }); |
155 if (instrumenting) { | 167 if (instrumenting) { |
156 id = ++lastMicrotaskId; | 168 id = ++lastMicrotaskId; |
157 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject"; | 169 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject"; |
158 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); | 170 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); |
159 } | 171 } |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
311 var status = GET_PRIVATE(this, promiseStateSymbol); | 323 var status = GET_PRIVATE(this, promiseStateSymbol); |
312 if (IS_UNDEFINED(status)) { | 324 if (IS_UNDEFINED(status)) { |
313 throw MakeTypeError(kNotAPromise, this); | 325 throw MakeTypeError(kNotAPromise, this); |
314 } | 326 } |
315 | 327 |
316 var constructor = SpeciesConstructor(this, GlobalPromise); | 328 var constructor = SpeciesConstructor(this, GlobalPromise); |
317 onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler; | 329 onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler; |
318 onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler; | 330 onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler; |
319 var deferred = NewPromiseCapability(constructor); | 331 var deferred = NewPromiseCapability(constructor); |
320 switch (status) { | 332 switch (status) { |
321 case kPending: | 333 case kPending: |
adamk
2016/05/25 19:18:57
This whole block seems like it should be encapsula
gsathya
2016/05/25 21:46:34
Done.
| |
322 GET_PRIVATE(this, promiseFulfillReactionsSymbol).push(onResolve, | 334 var resolveCallbacks = GET_PRIVATE(this, promiseFulfillReactionsSymbol); |
323 deferred); | 335 if (IS_NULL_OR_UNDEFINED(resolveCallbacks)) { |
324 GET_PRIVATE(this, promiseRejectReactionsSymbol).push(onReject, deferred); | 336 SET_PRIVATE(this, promiseDeferredReactionsSymbol, deferred); |
337 SET_PRIVATE(this, promiseFulfillReactionsSymbol, onResolve); | |
338 SET_PRIVATE(this, promiseRejectReactionsSymbol, onReject); | |
339 } else if (!IS_ARRAY(resolveCallbacks)) { | |
adamk
2016/05/25 19:18:57
Did you figure out if Bluebird goes down this path
gsathya
2016/05/25 21:46:35
Bluebird doesn't create arrays at all, they just s
adamk
2016/05/25 21:57:43
Sorry, when I say "Bluebird" I meant the benchmark
adamk
2016/05/25 23:41:35
As discussed offline, though this path isn't cover
| |
340 var deferreds = new InternalArray(); | |
341 var resolveCallbacks = new InternalArray(); | |
342 var rejectCallbacks = new InternalArray(); | |
343 | |
344 deferreds.push(GET_PRIVATE(this, promiseDeferredReactionsSymbol)); | |
345 resolveCallbacks.push(GET_PRIVATE(this, promiseFulfillReactionsSymbol)); | |
adamk
2016/05/25 19:18:57
This extra GET isn't needed, you already had an ar
gsathya
2016/05/25 21:46:35
Done. Let me know if you have a better name for th
| |
346 rejectCallbacks.push(GET_PRIVATE(this, promiseRejectReactionsSymbol)); | |
347 | |
348 deferreds.push(deferred); | |
349 resolveCallbacks.push(onResolve); | |
350 rejectCallbacks.push(onReject); | |
351 | |
352 SET_PRIVATE(this, promiseDeferredReactionsSymbol, deferreds); | |
353 SET_PRIVATE(this, promiseFulfillReactionsSymbol, resolveCallbacks); | |
354 SET_PRIVATE(this, promiseRejectReactionsSymbol, rejectCallbacks); | |
355 } else { | |
356 GET_PRIVATE(this, promiseDeferredReactionsSymbol).push(deferred); | |
357 GET_PRIVATE(this, promiseFulfillReactionsSymbol).push(onResolve); | |
adamk
2016/05/25 19:18:57
This extra GET isn't needed, you already have an a
gsathya
2016/05/25 21:46:35
Done.
| |
358 GET_PRIVATE(this, promiseRejectReactionsSymbol).push(onReject); | |
359 } | |
325 break; | 360 break; |
326 case kFulfilled: | 361 case kFulfilled: |
327 PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol), | 362 PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol), |
328 [onResolve, deferred], | 363 onResolve, deferred, |
329 kFulfilled); | 364 kFulfilled, 1); |
adamk
2016/05/25 19:18:57
Looks like a stray change from the previous approa
gsathya
2016/05/25 21:46:34
Done.
| |
330 break; | 365 break; |
331 case kRejected: | 366 case kRejected: |
332 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandlerSymbol)) { | 367 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandlerSymbol)) { |
333 // Promise has already been rejected, but had no handler. | 368 // Promise has already been rejected, but had no handler. |
334 // Revoke previously triggered reject event. | 369 // Revoke previously triggered reject event. |
335 %PromiseRevokeReject(this); | 370 %PromiseRevokeReject(this); |
336 } | 371 } |
337 PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol), | 372 PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol), |
338 [onReject, deferred], | 373 onReject, deferred, |
339 kRejected); | 374 kRejected, 1); |
adamk
2016/05/25 19:18:57
Same here.
gsathya
2016/05/25 21:46:35
Done.
| |
340 break; | 375 break; |
341 } | 376 } |
342 // Mark this promise as having handler. | 377 // Mark this promise as having handler. |
343 SET_PRIVATE(this, promiseHasHandlerSymbol, true); | 378 SET_PRIVATE(this, promiseHasHandlerSymbol, true); |
344 return deferred.promise; | 379 return deferred.promise; |
345 } | 380 } |
346 | 381 |
347 // Unspecified V8-specific legacy function | 382 // Unspecified V8-specific legacy function |
348 // Chain is left around for now as an alias for then | 383 // Chain is left around for now as an alias for then |
349 function PromiseChain(onResolve, onReject) { | 384 function PromiseChain(onResolve, onReject) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
440 deferred.reject(e) | 475 deferred.reject(e) |
441 } | 476 } |
442 return deferred.promise; | 477 return deferred.promise; |
443 } | 478 } |
444 | 479 |
445 | 480 |
446 // Utility for debugger | 481 // Utility for debugger |
447 | 482 |
448 function PromiseHasUserDefinedRejectHandlerRecursive(promise) { | 483 function PromiseHasUserDefinedRejectHandlerRecursive(promise) { |
449 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol); | 484 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol); |
485 var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol); | |
450 if (IS_UNDEFINED(queue)) return false; | 486 if (IS_UNDEFINED(queue)) return false; |
451 for (var i = 0; i < queue.length; i += 2) { | 487 if (!IS_ARRAY(queue)) { |
488 queue = [queue]; | |
adamk
2016/05/25 19:18:57
This is a neat trick, I'll have to think about whe
gsathya
2016/05/25 21:46:35
:P Happy to change it, let me know
adamk
2016/05/25 23:41:35
Please do change it to a factored-out function and
gsathya
2016/05/26 22:18:47
Done.
| |
489 deferreds = [deferreds]; | |
490 } | |
491 for (var i = 0; i < queue.length; i += 1) { | |
452 var handler = queue[i]; | 492 var handler = queue[i]; |
453 if (handler !== PromiseIdRejectHandler) { | 493 if (handler !== PromiseIdRejectHandler) { |
454 var deferred = GET_PRIVATE(handler, promiseCombinedDeferredSymbol); | 494 var combinedDeferred = |
455 if (IS_UNDEFINED(deferred)) return true; | 495 GET_PRIVATE(handler, promiseCombinedDeferredSymbol); |
456 if (PromiseHasUserDefinedRejectHandlerRecursive(deferred.promise)) { | 496 if (IS_UNDEFINED(combinedDeferred)) return true; |
497 if (PromiseHasUserDefinedRejectHandlerRecursive( | |
498 combinedDeferred.promise)) { | |
457 return true; | 499 return true; |
458 } | 500 } |
459 } else if (PromiseHasUserDefinedRejectHandlerRecursive( | 501 } else if (PromiseHasUserDefinedRejectHandlerRecursive( |
460 queue[i + 1].promise)) { | 502 deferreds[i].promise)) { |
461 return true; | 503 return true; |
462 } | 504 } |
463 } | 505 } |
464 return false; | 506 return false; |
465 } | 507 } |
466 | 508 |
467 // Return whether the promise will be handled by a user-defined reject | 509 // Return whether the promise will be handled by a user-defined reject |
468 // handler somewhere down the promise chain. For this, we do a depth-first | 510 // handler somewhere down the promise chain. For this, we do a depth-first |
469 // search for a reject handler that's not the default PromiseIdRejectHandler. | 511 // search for a reject handler that's not the default PromiseIdRejectHandler. |
470 function PromiseHasUserDefinedRejectHandler() { | 512 function PromiseHasUserDefinedRejectHandler() { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
519 to.PromiseChain = PromiseChain; | 561 to.PromiseChain = PromiseChain; |
520 to.PromiseDefer = PromiseDefer; | 562 to.PromiseDefer = PromiseDefer; |
521 to.PromiseAccept = PromiseAccept; | 563 to.PromiseAccept = PromiseAccept; |
522 | 564 |
523 to.PromiseCreateRejected = PromiseCreateRejected; | 565 to.PromiseCreateRejected = PromiseCreateRejected; |
524 to.PromiseCreateResolved = PromiseCreateResolved; | 566 to.PromiseCreateResolved = PromiseCreateResolved; |
525 to.PromiseThen = PromiseThen; | 567 to.PromiseThen = PromiseThen; |
526 }); | 568 }); |
527 | 569 |
528 }) | 570 }) |
OLD | NEW |