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

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

Issue 2317383002: Async/await Promise dependency graph (Closed)
Patch Set: format 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
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 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
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
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
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
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 })
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698