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

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

Issue 2007803002: Promises: Lazily create arrays to store resolve, reject callbacks (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Update cctest Created 4 years, 7 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/heap-symbols.h ('k') | test/cctest/test-inobject-slack-tracking.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 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
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
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
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
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 })
OLDNEW
« no previous file with comments | « src/heap-symbols.h ('k') | test/cctest/test-inobject-slack-tracking.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698