Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: src/js/promise.js

Issue 2317383002: Async/await Promise dependency graph (Closed)
Patch Set: Remove irrelevant whitespace change Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/js/prologue.js ('k') | src/parsing/parser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 promiseAwaitHandlerSymbol = 15 var promiseHandledBySymbol =
16 utils.ImportNow("promise_await_handler_symbol"); 16 utils.ImportNow("promise_handled_by_symbol");
17 var promiseCombinedDeferredSymbol = 17 var promiseForwardingHandlerSymbol =
18 utils.ImportNow("promise_combined_deferred_symbol"); 18 utils.ImportNow("promise_forwarding_handler_symbol");
19 var promiseHasHandlerSymbol = 19 var promiseHasHandlerSymbol =
20 utils.ImportNow("promise_has_handler_symbol"); 20 utils.ImportNow("promise_has_handler_symbol");
21 var promiseRejectReactionsSymbol = 21 var promiseRejectReactionsSymbol =
22 utils.ImportNow("promise_reject_reactions_symbol"); 22 utils.ImportNow("promise_reject_reactions_symbol");
23 var promiseFulfillReactionsSymbol = 23 var promiseFulfillReactionsSymbol =
24 utils.ImportNow("promise_fulfill_reactions_symbol"); 24 utils.ImportNow("promise_fulfill_reactions_symbol");
25 var promiseDeferredReactionsSymbol = 25 var promiseDeferredReactionsSymbol =
26 utils.ImportNow("promise_deferred_reactions_symbol"); 26 utils.ImportNow("promise_deferred_reactions_symbol");
27 var promiseHandledHintSymbol = 27 var promiseHandledHintSymbol =
28 utils.ImportNow("promise_handled_hint_symbol"); 28 utils.ImportNow("promise_handled_hint_symbol");
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks); 215 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks);
216 SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks); 216 SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks);
217 } else { 217 } else {
218 maybeResolveCallbacks.push(onResolve, deferred); 218 maybeResolveCallbacks.push(onResolve, deferred);
219 GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject, deferred); 219 GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject, deferred);
220 } 220 }
221 } 221 }
222 222
223 function PromiseIdResolveHandler(x) { return x; } 223 function PromiseIdResolveHandler(x) { return x; }
224 function PromiseIdRejectHandler(r) { %_ReThrow(r); } 224 function PromiseIdRejectHandler(r) { %_ReThrow(r); }
225 SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true);
225 226
226 function PromiseNopResolver() {} 227 function PromiseNopResolver() {}
227 228
228 // ------------------------------------------------------------------- 229 // -------------------------------------------------------------------
229 // Define exported functions. 230 // Define exported functions.
230 231
231 // For bootstrapper. 232 // For bootstrapper.
232 233
233 // ES#sec-ispromise IsPromise ( x ) 234 // ES#sec-ispromise IsPromise ( x )
234 function IsPromise(x) { 235 function IsPromise(x) {
235 return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol); 236 return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol);
236 } 237 }
237 238
238 function PromiseCreate() { 239 function PromiseCreate() {
239 return new GlobalPromise(PromiseNopResolver) 240 return new GlobalPromise(PromiseNopResolver);
240 } 241 }
241 242
242 // ES#sec-promise-resolve-functions 243 // ES#sec-promise-resolve-functions
243 // Promise Resolve Functions, steps 6-13 244 // Promise Resolve Functions, steps 6-13
244 function ResolvePromise(promise, resolution) { 245 function ResolvePromise(promise, resolution) {
245 if (resolution === promise) { 246 if (resolution === promise) {
246 return RejectPromise(promise, 247 return RejectPromise(promise,
247 %make_type_error(kPromiseCyclic, resolution), 248 %make_type_error(kPromiseCyclic, resolution),
248 true); 249 true);
249 } 250 }
(...skipping 30 matching lines...) Expand all
280 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); 281 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true);
281 return; 282 return;
282 } 283 }
283 } 284 }
284 285
285 if (IS_CALLABLE(then)) { 286 if (IS_CALLABLE(then)) {
286 // PromiseResolveThenableJob 287 // PromiseResolveThenableJob
287 var id; 288 var id;
288 var name = "PromiseResolveThenableJob"; 289 var name = "PromiseResolveThenableJob";
289 var instrumenting = DEBUG_IS_ACTIVE; 290 var instrumenting = DEBUG_IS_ACTIVE;
291 if (instrumenting && IsPromise(resolution)) {
292 // Mark the dependency of the new promise on the resolution
293 SET_PRIVATE(resolution, promiseHandledBySymbol, promise);
294 }
290 %EnqueueMicrotask(function() { 295 %EnqueueMicrotask(function() {
291 if (instrumenting) { 296 if (instrumenting) {
292 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); 297 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
293 } 298 }
294 // These resolving functions simply forward the exception, so 299 // These resolving functions simply forward the exception, so
295 // don't create a new debugEvent. 300 // don't create a new debugEvent.
296 var callbacks = CreateResolvingFunctions(promise, false); 301 var callbacks = CreateResolvingFunctions(promise, false);
297 try { 302 try {
298 %_Call(then, resolution, callbacks.resolve, callbacks.reject); 303 %_Call(then, resolution, callbacks.resolve, callbacks.reject);
299 } catch (e) { 304 } catch (e) {
300 %_Call(callbacks.reject, UNDEFINED, e); 305 %_Call(callbacks.reject, UNDEFINED, e);
301 } 306 }
302 if (instrumenting) { 307 if (instrumenting) {
303 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); 308 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
304 } 309 }
305 }); 310 });
306 if (instrumenting) { 311 if (instrumenting) {
307 id = ++lastMicrotaskId; 312 id = ++lastMicrotaskId;
308 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); 313 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
309 } 314 }
310 return; 315 return;
311 } 316 }
312 } 317 }
313 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ; 318 FulfillPromise(promise, kFulfilled, resolution,
319 promiseFulfillReactionsSymbol);
314 } 320 }
315 321
316 // ES#sec-rejectpromise 322 // ES#sec-rejectpromise
317 // RejectPromise ( promise, reason ) 323 // RejectPromise ( promise, reason )
318 function RejectPromise(promise, reason, debugEvent) { 324 function RejectPromise(promise, reason, debugEvent) {
319 // Check promise status to confirm that this reject has an effect. 325 // Check promise status to confirm that this reject has an effect.
320 // Call runtime for callbacks to the debugger or for unhandled reject. 326 // Call runtime for callbacks to the debugger or for unhandled reject.
321 // The debugEvent parameter sets whether a debug ExceptionEvent should 327 // The debugEvent parameter sets whether a debug ExceptionEvent should
322 // be triggered. It should be set to false when forwarding a rejection 328 // be triggered. It should be set to false when forwarding a rejection
323 // rather than creating a new one. 329 // rather than creating a new one.
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 if (!IS_RECEIVER(this)) { 471 if (!IS_RECEIVER(this)) {
466 throw %make_type_error(kCalledOnNonObject, "Promise.all"); 472 throw %make_type_error(kCalledOnNonObject, "Promise.all");
467 } 473 }
468 474
469 // false debugEvent so that forwarding the rejection through all does not 475 // false debugEvent so that forwarding the rejection through all does not
470 // trigger redundant ExceptionEvents 476 // trigger redundant ExceptionEvents
471 var deferred = NewPromiseCapability(this, false); 477 var deferred = NewPromiseCapability(this, false);
472 var resolutions = new InternalArray(); 478 var resolutions = new InternalArray();
473 var count; 479 var count;
474 480
481 // For catch prediction, don't treat the .then calls as handling it;
482 // instead, recurse outwards.
483 SET_PRIVATE(deferred.reject, promiseForwardingHandlerSymbol, true);
484
475 function CreateResolveElementFunction(index, values, promiseCapability) { 485 function CreateResolveElementFunction(index, values, promiseCapability) {
476 var alreadyCalled = false; 486 var alreadyCalled = false;
477 return (x) => { 487 return (x) => {
478 if (alreadyCalled === true) return; 488 if (alreadyCalled === true) return;
479 alreadyCalled = true; 489 alreadyCalled = true;
480 values[index] = x; 490 values[index] = x;
481 if (--count === 0) { 491 if (--count === 0) {
482 var valuesArray = []; 492 var valuesArray = [];
483 %MoveArrayContents(values, valuesArray); 493 %MoveArrayContents(values, valuesArray);
484 %_Call(promiseCapability.resolve, UNDEFINED, valuesArray); 494 %_Call(promiseCapability.resolve, UNDEFINED, valuesArray);
485 } 495 }
486 }; 496 };
487 } 497 }
488 498
489 try { 499 try {
490 var i = 0; 500 var i = 0;
491 count = 1; 501 count = 1;
492 for (var value of iterable) { 502 for (var value of iterable) {
493 var nextPromise = this.resolve(value); 503 var nextPromise = this.resolve(value);
494 ++count; 504 ++count;
495 nextPromise.then( 505 let throwawayPromise = nextPromise.then(
adamk 2016/09/17 00:32:40 This is the first "let" in this file (or anywhere
Dan Ehrenberg 2016/09/17 00:39:31 Fixed
496 CreateResolveElementFunction(i, resolutions, deferred), 506 CreateResolveElementFunction(i, resolutions, deferred),
497 deferred.reject); 507 deferred.reject);
498 SET_PRIVATE(deferred.reject, promiseCombinedDeferredSymbol, deferred); 508 // For catch prediction, mark that rejections here are semantically
509 // handled by the combined Promise.
510 if (IsPromise(throwawayPromise)) {
511 SET_PRIVATE(throwawayPromise, promiseHandledBySymbol, deferred.promise);
512 }
499 ++i; 513 ++i;
500 } 514 }
501 515
502 // 6.d 516 // 6.d
503 if (--count === 0) { 517 if (--count === 0) {
504 var valuesArray = []; 518 var valuesArray = [];
505 %MoveArrayContents(resolutions, valuesArray); 519 %MoveArrayContents(resolutions, valuesArray);
506 %_Call(deferred.resolve, UNDEFINED, valuesArray); 520 %_Call(deferred.resolve, UNDEFINED, valuesArray);
507 } 521 }
508 522
509 } catch (e) { 523 } catch (e) {
510 %_Call(deferred.reject, UNDEFINED, e); 524 %_Call(deferred.reject, UNDEFINED, e);
511 } 525 }
512 return deferred.promise; 526 return deferred.promise;
513 } 527 }
514 528
515 // ES#sec-promise.race 529 // ES#sec-promise.race
516 // Promise.race ( iterable ) 530 // Promise.race ( iterable )
517 function PromiseRace(iterable) { 531 function PromiseRace(iterable) {
518 if (!IS_RECEIVER(this)) { 532 if (!IS_RECEIVER(this)) {
519 throw %make_type_error(kCalledOnNonObject, PromiseRace); 533 throw %make_type_error(kCalledOnNonObject, PromiseRace);
520 } 534 }
521 535
522 // false debugEvent so that forwarding the rejection through race does not 536 // false debugEvent so that forwarding the rejection through race does not
523 // trigger redundant ExceptionEvents 537 // trigger redundant ExceptionEvents
524 var deferred = NewPromiseCapability(this, false); 538 var deferred = NewPromiseCapability(this, false);
539
540 // For catch prediction, don't treat the .then calls as handling it;
541 // instead, recurse outwards.
542 SET_PRIVATE(deferred.reject, promiseForwardingHandlerSymbol, true);
543
525 try { 544 try {
526 for (var value of iterable) { 545 for (var value of iterable) {
527 this.resolve(value).then(deferred.resolve, deferred.reject); 546 var throwawayPromise = this.resolve(value).then(deferred.resolve,
528 SET_PRIVATE(deferred.reject, promiseCombinedDeferredSymbol, deferred); 547 deferred.reject);
548 // For catch prediction, mark that rejections here are semantically
549 // handled by the combined Promise.
550 if (IsPromise(throwawayPromise)) {
551 SET_PRIVATE(throwawayPromise, promiseHandledBySymbol, deferred.promise);
552 }
529 } 553 }
530 } catch (e) { 554 } catch (e) {
531 deferred.reject(e) 555 deferred.reject(e)
532 } 556 }
533 return deferred.promise; 557 return deferred.promise;
534 } 558 }
535 559
536 560
537 // Utility for debugger 561 // Utility for debugger
538 562
539 function PromiseHasUserDefinedRejectHandlerCheck(handler, deferred) { 563 function PromiseHasUserDefinedRejectHandlerCheck(handler, deferred) {
540 // If this handler was installed by async/await, it does not indicate 564 // Recurse to the forwarding Promise, if any. This may be due to
541 // that there is a user-defined reject handler. 565 // - await reaction forwarding to the throwaway Promise, which has
542 if (GET_PRIVATE(handler, promiseAwaitHandlerSymbol)) return false; 566 // a dependency edge to the outer Promise.
543 if (handler !== PromiseIdRejectHandler) { 567 // - PromiseIdResolveHandler forwarding to the output of .then
544 var combinedDeferred = GET_PRIVATE(handler, promiseCombinedDeferredSymbol); 568 // - Promise.all/Promise.race forwarding to a throwaway Promise, which
545 if (IS_UNDEFINED(combinedDeferred)) return true; 569 // has a dependency edge to the generated outer Promise.
546 if (PromiseHasUserDefinedRejectHandlerRecursive(combinedDeferred.promise)) { 570 if (GET_PRIVATE(handler, promiseForwardingHandlerSymbol)) {
547 return true; 571 return PromiseHasUserDefinedRejectHandlerRecursive(deferred.promise);
548 }
549 } else if (PromiseHasUserDefinedRejectHandlerRecursive(deferred.promise)) {
550 return true;
551 } 572 }
552 return false; 573
574 // Otherwise, this is a real reject handler for the Promise
575 return true;
553 } 576 }
554 577
555 function PromiseHasUserDefinedRejectHandlerRecursive(promise) { 578 function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
556 // If this promise was marked as being handled by a catch block 579 // 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. 580 // in an async function, then it has a user-defined reject handler.
558 if (GET_PRIVATE(promise, promiseHandledHintSymbol)) return true; 581 if (GET_PRIVATE(promise, promiseHandledHintSymbol)) return true;
559 582
583 // If this Promise is subsumed by another Promise (a Promise resolved
584 // with another Promise, or an intermediate, hidden, throwaway Promise
585 // within async/await), then recurse on the outer Promise.
586 // In this case, the dependency is one possible way that the Promise
587 // could be resolved, so it does not subsume the other following cases.
588 var outerPromise = GET_PRIVATE(promise, promiseHandledBySymbol);
589 if (outerPromise &&
590 PromiseHasUserDefinedRejectHandlerRecursive(outerPromise)) {
591 return true;
592 }
593
560 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol); 594 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol);
561 var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol); 595 var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol);
562 596
563 if (IS_UNDEFINED(queue)) return false; 597 if (IS_UNDEFINED(queue)) return false;
564 598
565 if (!IS_ARRAY(queue)) { 599 if (!IS_ARRAY(queue)) {
566 return PromiseHasUserDefinedRejectHandlerCheck(queue, deferreds); 600 return PromiseHasUserDefinedRejectHandlerCheck(queue, deferreds);
567 } 601 }
568 602
569 for (var i = 0; i < queue.length; i += 2) { 603 for (var i = 0; i < queue.length; i += 2) {
570 if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], queue[i + 1])) { 604 if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], queue[i + 1])) {
571 return true; 605 return true;
572 } 606 }
573 } 607 }
574 return false; 608 return false;
575 } 609 }
576 610
577 // Return whether the promise will be handled by a user-defined reject 611 // 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 612 // 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. 613 // search for a reject handler that's not the default PromiseIdRejectHandler.
614 // This function also traverses dependencies of one Promise on another,
615 // set up through async/await and Promises resolved with Promises.
580 function PromiseHasUserDefinedRejectHandler() { 616 function PromiseHasUserDefinedRejectHandler() {
581 return PromiseHasUserDefinedRejectHandlerRecursive(this); 617 return PromiseHasUserDefinedRejectHandlerRecursive(this);
582 }; 618 };
583 619
584 620
585 function PromiseSpecies() { 621 function PromiseSpecies() {
586 return this; 622 return this;
587 } 623 }
588 624
589 // ------------------------------------------------------------------- 625 // -------------------------------------------------------------------
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 to.PromiseThen = PromiseThen; 667 to.PromiseThen = PromiseThen;
632 668
633 to.GlobalPromise = GlobalPromise; 669 to.GlobalPromise = GlobalPromise;
634 to.NewPromiseCapability = NewPromiseCapability; 670 to.NewPromiseCapability = NewPromiseCapability;
635 to.PerformPromiseThen = PerformPromiseThen; 671 to.PerformPromiseThen = PerformPromiseThen;
636 to.ResolvePromise = ResolvePromise; 672 to.ResolvePromise = ResolvePromise;
637 to.RejectPromise = RejectPromise; 673 to.RejectPromise = RejectPromise;
638 }); 674 });
639 675
640 }) 676 })
OLDNEW
« no previous file with comments | « src/js/prologue.js ('k') | src/parsing/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698