Chromium Code Reviews| 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 GlobalSet = global.Set; | |
| 15 var promiseAwaitHandlerSymbol = | 16 var promiseAwaitHandlerSymbol = |
| 16 utils.ImportNow("promise_await_handler_symbol"); | 17 utils.ImportNow("promise_await_handler_symbol"); |
| 17 var promiseCombinedDeferredSymbol = | 18 var promiseCombinedDeferredSymbol = |
| 18 utils.ImportNow("promise_combined_deferred_symbol"); | 19 utils.ImportNow("promise_combined_deferred_symbol"); |
| 19 var promiseHasHandlerSymbol = | 20 var promiseHasHandlerSymbol = |
| 20 utils.ImportNow("promise_has_handler_symbol"); | 21 utils.ImportNow("promise_has_handler_symbol"); |
| 21 var promiseRejectReactionsSymbol = | 22 var promiseRejectReactionsSymbol = |
| 22 utils.ImportNow("promise_reject_reactions_symbol"); | 23 utils.ImportNow("promise_reject_reactions_symbol"); |
| 23 var promiseFulfillReactionsSymbol = | 24 var promiseFulfillReactionsSymbol = |
| 24 utils.ImportNow("promise_fulfill_reactions_symbol"); | 25 utils.ImportNow("promise_fulfill_reactions_symbol"); |
| 25 var promiseDeferredReactionsSymbol = | 26 var promiseDeferredReactionsSymbol = |
| 26 utils.ImportNow("promise_deferred_reactions_symbol"); | 27 utils.ImportNow("promise_deferred_reactions_symbol"); |
| 27 var promiseHandledHintSymbol = | 28 var promiseHandledHintSymbol = |
| 28 utils.ImportNow("promise_handled_hint_symbol"); | 29 utils.ImportNow("promise_handled_hint_symbol"); |
| 29 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); | 30 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); |
| 30 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); | 31 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); |
| 31 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); | 32 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); |
| 33 var SetAdd; | |
| 34 var SetHas; | |
| 32 var SpeciesConstructor; | 35 var SpeciesConstructor; |
| 33 var speciesSymbol = utils.ImportNow("species_symbol"); | 36 var speciesSymbol = utils.ImportNow("species_symbol"); |
| 34 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); | 37 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); |
| 35 | 38 |
| 36 utils.Import(function(from) { | 39 utils.Import(function(from) { |
| 37 SpeciesConstructor = from.SpeciesConstructor; | 40 SpeciesConstructor = from.SpeciesConstructor; |
| 41 SetAdd = from.SetAdd; | |
|
adamk
2016/09/15 22:39:40
Nit: sort
Dan Ehrenberg
2016/09/17 00:04:31
Done
| |
| 42 SetHas = from.SetHas; | |
| 38 }); | 43 }); |
| 39 | 44 |
| 40 // ------------------------------------------------------------------- | 45 // ------------------------------------------------------------------- |
| 41 | 46 |
| 42 // [[PromiseState]] values: | 47 // [[PromiseState]] values: |
| 43 const kPending = 0; | 48 const kPending = 0; |
| 44 const kFulfilled = +1; | 49 const kFulfilled = +1; |
| 45 const kRejected = -1; | 50 const kRejected = -1; |
| 46 | 51 |
| 47 var lastMicrotaskId = 0; | 52 var lastMicrotaskId = 0; |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 229 // Define exported functions. | 234 // Define exported functions. |
| 230 | 235 |
| 231 // For bootstrapper. | 236 // For bootstrapper. |
| 232 | 237 |
| 233 // ES#sec-ispromise IsPromise ( x ) | 238 // ES#sec-ispromise IsPromise ( x ) |
| 234 function IsPromise(x) { | 239 function IsPromise(x) { |
| 235 return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol); | 240 return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol); |
| 236 } | 241 } |
| 237 | 242 |
| 238 function PromiseCreate() { | 243 function PromiseCreate() { |
| 239 return new GlobalPromise(PromiseNopResolver) | 244 return new GlobalPromise(PromiseNopResolver); |
| 240 } | 245 } |
| 241 | 246 |
| 242 // ES#sec-promise-resolve-functions | 247 // ES#sec-promise-resolve-functions |
| 243 // Promise Resolve Functions, steps 6-13 | 248 // Promise Resolve Functions, steps 6-13 |
| 244 function ResolvePromise(promise, resolution) { | 249 function ResolvePromise(promise, resolution) { |
| 245 if (resolution === promise) { | 250 if (resolution === promise) { |
| 246 return RejectPromise(promise, | 251 return RejectPromise(promise, |
| 247 %make_type_error(kPromiseCyclic, resolution), | 252 %make_type_error(kPromiseCyclic, resolution), |
| 248 true); | 253 true); |
| 249 } | 254 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 280 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); | 285 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); |
| 281 return; | 286 return; |
| 282 } | 287 } |
| 283 } | 288 } |
| 284 | 289 |
| 285 if (IS_CALLABLE(then)) { | 290 if (IS_CALLABLE(then)) { |
| 286 // PromiseResolveThenableJob | 291 // PromiseResolveThenableJob |
| 287 var id; | 292 var id; |
| 288 var name = "PromiseResolveThenableJob"; | 293 var name = "PromiseResolveThenableJob"; |
| 289 var instrumenting = DEBUG_IS_ACTIVE; | 294 var instrumenting = DEBUG_IS_ACTIVE; |
| 295 if (instrumenting && !IS_UNDEFINED(resolution) && | |
|
adamk
2016/09/15 22:39:40
No need to check !IS_UNDEFINED if you're checking
Dan Ehrenberg
2016/09/17 00:04:31
Done
| |
| 296 IsPromise(resolution)) { | |
| 297 // Mark the dependency of the new promise on the resolution | |
| 298 SET_PRIVATE(resolution, promiseAwaitHandlerSymbol, promise); | |
| 299 } | |
| 290 %EnqueueMicrotask(function() { | 300 %EnqueueMicrotask(function() { |
| 291 if (instrumenting) { | 301 if (instrumenting) { |
| 292 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); | 302 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); |
| 293 } | 303 } |
| 294 // These resolving functions simply forward the exception, so | 304 // These resolving functions simply forward the exception, so |
| 295 // don't create a new debugEvent. | 305 // don't create a new debugEvent. |
| 296 var callbacks = CreateResolvingFunctions(promise, false); | 306 var callbacks = CreateResolvingFunctions(promise, false); |
| 297 try { | 307 try { |
| 298 %_Call(then, resolution, callbacks.resolve, callbacks.reject); | 308 %_Call(then, resolution, callbacks.resolve, callbacks.reject); |
| 299 } catch (e) { | 309 } catch (e) { |
| 300 %_Call(callbacks.reject, UNDEFINED, e); | 310 %_Call(callbacks.reject, UNDEFINED, e); |
| 301 } | 311 } |
| 302 if (instrumenting) { | 312 if (instrumenting) { |
| 303 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); | 313 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); |
| 304 } | 314 } |
| 305 }); | 315 }); |
| 306 if (instrumenting) { | 316 if (instrumenting) { |
| 307 id = ++lastMicrotaskId; | 317 id = ++lastMicrotaskId; |
| 308 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); | 318 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); |
| 309 } | 319 } |
| 310 return; | 320 return; |
| 311 } | 321 } |
| 312 } | 322 } |
| 313 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ; | 323 FulfillPromise(promise, kFulfilled, resolution, |
| 324 promiseFulfillReactionsSymbol); | |
| 314 } | 325 } |
| 315 | 326 |
| 316 // ES#sec-rejectpromise | 327 // ES#sec-rejectpromise |
| 317 // RejectPromise ( promise, reason ) | 328 // RejectPromise ( promise, reason ) |
| 318 function RejectPromise(promise, reason, debugEvent) { | 329 function RejectPromise(promise, reason, debugEvent) { |
| 319 // Check promise status to confirm that this reject has an effect. | 330 // Check promise status to confirm that this reject has an effect. |
| 320 // Call runtime for callbacks to the debugger or for unhandled reject. | 331 // Call runtime for callbacks to the debugger or for unhandled reject. |
| 321 // The debugEvent parameter sets whether a debug ExceptionEvent should | 332 // The debugEvent parameter sets whether a debug ExceptionEvent should |
| 322 // be triggered. It should be set to false when forwarding a rejection | 333 // be triggered. It should be set to false when forwarding a rejection |
| 323 // rather than creating a new one. | 334 // rather than creating a new one. |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 529 } | 540 } |
| 530 } catch (e) { | 541 } catch (e) { |
| 531 deferred.reject(e) | 542 deferred.reject(e) |
| 532 } | 543 } |
| 533 return deferred.promise; | 544 return deferred.promise; |
| 534 } | 545 } |
| 535 | 546 |
| 536 | 547 |
| 537 // Utility for debugger | 548 // Utility for debugger |
| 538 | 549 |
| 539 function PromiseHasUserDefinedRejectHandlerCheck(handler, deferred) { | 550 function PromiseHasUserDefinedRejectHandlerCheck(handler, deferred, visited) { |
| 540 // If this handler was installed by async/await, it does not indicate | 551 // If this handler was installed by a locally uncaught await, recurse |
| 541 // that there is a user-defined reject handler. | 552 // up to the outer Promise returned by that async function. |
| 542 if (GET_PRIVATE(handler, promiseAwaitHandlerSymbol)) return false; | 553 // In this case, the dependency subsumes any other things attached to the |
| 554 // handler, as the dependency is only present due to async/await and is not | |
| 555 // a real catch handler. | |
| 556 var outerPromise = GET_PRIVATE(handler, promiseAwaitHandlerSymbol); | |
| 557 if (outerPromise) { | |
| 558 return PromiseHasUserDefinedRejectHandlerRecursive(outerPromise, visited); | |
| 559 } | |
| 543 if (handler !== PromiseIdRejectHandler) { | 560 if (handler !== PromiseIdRejectHandler) { |
| 544 var combinedDeferred = GET_PRIVATE(handler, promiseCombinedDeferredSymbol); | 561 var combinedDeferred = GET_PRIVATE(handler, promiseCombinedDeferredSymbol); |
| 545 if (IS_UNDEFINED(combinedDeferred)) return true; | 562 if (IS_UNDEFINED(combinedDeferred)) return true; |
| 546 if (PromiseHasUserDefinedRejectHandlerRecursive(combinedDeferred.promise)) { | 563 if (PromiseHasUserDefinedRejectHandlerRecursive(combinedDeferred.promise, |
| 564 visited)) { | |
| 547 return true; | 565 return true; |
| 548 } | 566 } |
| 549 } else if (PromiseHasUserDefinedRejectHandlerRecursive(deferred.promise)) { | 567 } else if (PromiseHasUserDefinedRejectHandlerRecursive(deferred.promise, |
| 568 visited)) { | |
| 550 return true; | 569 return true; |
| 551 } | 570 } |
| 552 return false; | 571 return false; |
| 553 } | 572 } |
| 554 | 573 |
| 555 function PromiseHasUserDefinedRejectHandlerRecursive(promise) { | 574 function PromiseHasUserDefinedRejectHandlerRecursive(promise, visited) { |
| 575 // Avoid visiting the Promise multiple times in case there is a cycle | |
| 576 // in the dependency graph. | |
| 577 if (%_Call(SetHas, visited, promise)) return false; | |
|
adamk
2016/09/15 22:39:40
My brain is having trouble groking all the tests;
| |
| 578 %_Call(SetAdd, visited, promise); | |
| 579 | |
| 556 // If this promise was marked as being handled by a catch block | 580 // If this promise was marked as being handled by a catch block |
| 557 // in an async function, then it has a user-defined reject handler. | 581 // in an async function, then it has a user-defined reject handler. |
| 558 if (GET_PRIVATE(promise, promiseHandledHintSymbol)) return true; | 582 if (GET_PRIVATE(promise, promiseHandledHintSymbol)) return true; |
| 559 | 583 |
| 584 // If this Promise is subsumed by another Promise (a Promise resolved | |
| 585 // with another Promise, or an intermediate, hidden, throwaway Promise | |
| 586 // within async/await), then recurse on the outer Promise. | |
| 587 // In this case, the dependency is one possible way that the Promise | |
| 588 // could be resolved, so it does not subsume the other following cases. | |
| 589 var outerPromise = GET_PRIVATE(promise, promiseAwaitHandlerSymbol); | |
| 590 if (outerPromise && | |
| 591 PromiseHasUserDefinedRejectHandlerRecursive(outerPromise, visited)) { | |
| 592 return true; | |
| 593 } | |
| 594 | |
| 560 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol); | 595 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol); |
| 561 var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol); | 596 var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol); |
| 562 | 597 |
| 563 if (IS_UNDEFINED(queue)) return false; | 598 if (IS_UNDEFINED(queue)) return false; |
| 564 | 599 |
| 565 if (!IS_ARRAY(queue)) { | 600 if (!IS_ARRAY(queue)) { |
| 566 return PromiseHasUserDefinedRejectHandlerCheck(queue, deferreds); | 601 return PromiseHasUserDefinedRejectHandlerCheck(queue, deferreds, visited); |
| 567 } | 602 } |
| 568 | 603 |
| 569 for (var i = 0; i < queue.length; i += 2) { | 604 for (var i = 0; i < queue.length; i += 2) { |
| 570 if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], queue[i + 1])) { | 605 if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], |
| 606 queue[i + 1], | |
| 607 visited)) { | |
| 571 return true; | 608 return true; |
| 572 } | 609 } |
| 573 } | 610 } |
| 574 return false; | 611 return false; |
| 575 } | 612 } |
| 576 | 613 |
| 577 // Return whether the promise will be handled by a user-defined reject | 614 // Return whether the promise will be handled by a user-defined reject |
| 578 // handler somewhere down the promise chain. For this, we do a depth-first | 615 // handler somewhere down the promise chain. For this, we do a depth-first |
| 579 // search for a reject handler that's not the default PromiseIdRejectHandler. | 616 // search for a reject handler that's not the default PromiseIdRejectHandler. |
| 617 // This function also traverses dependencies of one Promise on another, | |
| 618 // set up through async/await and Promises resolved with Promises. The graph | |
| 619 // may contain cycles, so a set of visited Promises is maintained. | |
| 580 function PromiseHasUserDefinedRejectHandler() { | 620 function PromiseHasUserDefinedRejectHandler() { |
| 581 return PromiseHasUserDefinedRejectHandlerRecursive(this); | 621 return PromiseHasUserDefinedRejectHandlerRecursive(this, new GlobalSet()); |
| 582 }; | 622 }; |
| 583 | 623 |
| 584 | 624 |
| 585 function PromiseSpecies() { | 625 function PromiseSpecies() { |
| 586 return this; | 626 return this; |
| 587 } | 627 } |
| 588 | 628 |
| 589 // ------------------------------------------------------------------- | 629 // ------------------------------------------------------------------- |
| 590 // Install exported functions. | 630 // Install exported functions. |
| 591 | 631 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 631 to.PromiseThen = PromiseThen; | 671 to.PromiseThen = PromiseThen; |
| 632 | 672 |
| 633 to.GlobalPromise = GlobalPromise; | 673 to.GlobalPromise = GlobalPromise; |
| 634 to.NewPromiseCapability = NewPromiseCapability; | 674 to.NewPromiseCapability = NewPromiseCapability; |
| 635 to.PerformPromiseThen = PerformPromiseThen; | 675 to.PerformPromiseThen = PerformPromiseThen; |
| 636 to.ResolvePromise = ResolvePromise; | 676 to.ResolvePromise = ResolvePromise; |
| 637 to.RejectPromise = RejectPromise; | 677 to.RejectPromise = RejectPromise; |
| 638 }); | 678 }); |
| 639 | 679 |
| 640 }) | 680 }) |
| OLD | NEW |