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

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: minor cleanup Created 4 years, 6 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(promise, status, value) {
102 SET_PRIVATE(promise, promiseStateSymbol, status); 104 SET_PRIVATE(promise, promiseStateSymbol, status);
103 SET_PRIVATE(promise, promiseResultSymbol, value); 105 SET_PRIVATE(promise, promiseResultSymbol, value);
104 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve); 106
105 SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject); 107 // There are 3 possible states for the resolve, reject symbols when we add
108 // a new callback --
109 // 1) UNDEFINED -- This is the zero state where there is no callback
110 // registered. When we see this state, we directly attach the callbacks to
111 // the symbol.
112 // 2) !IS_ARRAY -- There is a single callback directly attached to the
113 // symbols. We need to create a new array to store additional callbacks.
114 // 3) IS_ARRAY -- There are multiple callbacks already registered,
115 // therefore we can just push the new callback to the existing array.
116 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, UNDEFINED);
117 SET_PRIVATE(promise, promiseRejectReactionsSymbol, UNDEFINED);
118 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, UNDEFINED);
106 return promise; 119 return promise;
107 } 120 }
108 121
109 function PromiseCreateAndSet(status, value) { 122 function PromiseCreateAndSet(status, value) {
110 var promise = new GlobalPromise(promiseRawSymbol); 123 var promise = new GlobalPromise(promiseRawSymbol);
111 // If debug is active, notify about the newly created promise first. 124 // If debug is active, notify about the newly created promise first.
112 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED); 125 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED);
113 return PromiseSet(promise, status, value); 126 return PromiseSet(promise, status, value);
114 } 127 }
115 128
116 function PromiseInit(promise) { 129 function PromiseInit(promise) {
117 return PromiseSet( 130 return PromiseSet(
118 promise, kPending, UNDEFINED, new InternalArray, new InternalArray) 131 promise, kPending, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED);
119 } 132 }
120 133
121 function FulfillPromise(promise, status, value, promiseQueue) { 134 function FulfillPromise(promise, status, value, promiseQueue) {
122 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { 135 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) {
123 var tasks = GET_PRIVATE(promise, promiseQueue); 136 var tasks = GET_PRIVATE(promise, promiseQueue);
124 if (tasks.length) PromiseEnqueue(value, tasks, status); 137 if (!IS_UNDEFINED(tasks)) {
138 var tasks = GET_PRIVATE(promise, promiseQueue);
139 var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol);
140 PromiseEnqueue(value, tasks, deferreds, status);
141 }
125 PromiseSet(promise, status, value); 142 PromiseSet(promise, status, value);
126 } 143 }
127 } 144 }
128 145
129 function PromiseHandle(value, handler, deferred) { 146 function PromiseHandle(value, handler, deferred) {
130 var debug_is_active = DEBUG_IS_ACTIVE; 147 var debug_is_active = DEBUG_IS_ACTIVE;
131 try { 148 try {
132 if (debug_is_active) %DebugPushPromise(deferred.promise, PromiseHandle); 149 if (debug_is_active) %DebugPushPromise(deferred.promise, PromiseHandle);
133 var result = handler(value); 150 var result = handler(value);
134 deferred.resolve(result); 151 deferred.resolve(result);
135 } catch (exception) { 152 } catch (exception) {
136 try { deferred.reject(exception); } catch (e) { } 153 try { deferred.reject(exception); } catch (e) { }
137 } finally { 154 } finally {
138 if (debug_is_active) %DebugPopPromise(); 155 if (debug_is_active) %DebugPopPromise();
139 } 156 }
140 } 157 }
141 158
142 function PromiseEnqueue(value, tasks, status) { 159 function PromiseEnqueue(value, tasks, deferreds, status) {
143 var id, name, instrumenting = DEBUG_IS_ACTIVE; 160 var id, name, instrumenting = DEBUG_IS_ACTIVE;
144 %EnqueueMicrotask(function() { 161 %EnqueueMicrotask(function() {
145 if (instrumenting) { 162 if (instrumenting) {
146 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); 163 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
147 } 164 }
148 for (var i = 0; i < tasks.length; i += 2) { 165 if (IS_ARRAY(tasks)) {
149 PromiseHandle(value, tasks[i], tasks[i + 1]) 166 for (var i = 0; i < tasks.length; i += 1) {
167 PromiseHandle(value, tasks[i], deferreds[i]);
168 }
169 } else {
170 PromiseHandle(value, tasks, deferreds);
150 } 171 }
151 if (instrumenting) { 172 if (instrumenting) {
152 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); 173 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
153 } 174 }
154 }); 175 });
155 if (instrumenting) { 176 if (instrumenting) {
156 id = ++lastMicrotaskId; 177 id = ++lastMicrotaskId;
157 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject"; 178 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject";
158 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); 179 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
159 } 180 }
160 } 181 }
161 182
183 function PromiseAttachCallbacks(promise, deferred, onResolve, onReject) {
184 var maybeResolveCallbacks =
185 GET_PRIVATE(promise, promiseFulfillReactionsSymbol);
186 if (IS_UNDEFINED(maybeResolveCallbacks)) {
187 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve);
188 SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject);
189 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, deferred);
190 } else if (!IS_ARRAY(maybeResolveCallbacks)) {
191 var resolveCallbacks = new InternalArray();
192 var rejectCallbacks = new InternalArray();
193 var deferreds = new InternalArray();
194
195 resolveCallbacks.push(maybeResolveCallbacks);
196 rejectCallbacks.push(GET_PRIVATE(promise, promiseRejectReactionsSymbol));
197 deferreds.push(GET_PRIVATE(promise, promiseDeferredReactionsSymbol));
198
199 resolveCallbacks.push(onResolve);
200 rejectCallbacks.push(onReject);
201 deferreds.push(deferred);
202
203 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks);
204 SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks);
205 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, deferreds);
206 } else {
207 maybeResolveCallbacks.push(onResolve);
208 GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject);
209 GET_PRIVATE(promise, promiseDeferredReactionsSymbol).push(deferred);
210 }
211 }
212
162 function PromiseIdResolveHandler(x) { return x } 213 function PromiseIdResolveHandler(x) { return x }
163 function PromiseIdRejectHandler(r) { throw r } 214 function PromiseIdRejectHandler(r) { throw r }
164 215
165 function PromiseNopResolver() {} 216 function PromiseNopResolver() {}
166 217
167 // ------------------------------------------------------------------- 218 // -------------------------------------------------------------------
168 // Define exported functions. 219 // Define exported functions.
169 220
170 // For bootstrapper. 221 // For bootstrapper.
171 222
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 if (IS_UNDEFINED(status)) { 363 if (IS_UNDEFINED(status)) {
313 throw MakeTypeError(kNotAPromise, this); 364 throw MakeTypeError(kNotAPromise, this);
314 } 365 }
315 366
316 var constructor = SpeciesConstructor(this, GlobalPromise); 367 var constructor = SpeciesConstructor(this, GlobalPromise);
317 onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler; 368 onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler;
318 onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler; 369 onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler;
319 var deferred = NewPromiseCapability(constructor); 370 var deferred = NewPromiseCapability(constructor);
320 switch (status) { 371 switch (status) {
321 case kPending: 372 case kPending:
322 GET_PRIVATE(this, promiseFulfillReactionsSymbol).push(onResolve, 373 PromiseAttachCallbacks(this, deferred, onResolve, onReject);
323 deferred);
324 GET_PRIVATE(this, promiseRejectReactionsSymbol).push(onReject, deferred);
325 break; 374 break;
326 case kFulfilled: 375 case kFulfilled:
327 PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol), 376 PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol),
328 [onResolve, deferred], 377 onResolve, deferred, kFulfilled);
329 kFulfilled);
330 break; 378 break;
331 case kRejected: 379 case kRejected:
332 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandlerSymbol)) { 380 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandlerSymbol)) {
333 // Promise has already been rejected, but had no handler. 381 // Promise has already been rejected, but had no handler.
334 // Revoke previously triggered reject event. 382 // Revoke previously triggered reject event.
335 %PromiseRevokeReject(this); 383 %PromiseRevokeReject(this);
336 } 384 }
337 PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol), 385 PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol),
338 [onReject, deferred], 386 onReject, deferred, kRejected);
339 kRejected);
340 break; 387 break;
341 } 388 }
342 // Mark this promise as having handler. 389 // Mark this promise as having handler.
343 SET_PRIVATE(this, promiseHasHandlerSymbol, true); 390 SET_PRIVATE(this, promiseHasHandlerSymbol, true);
344 return deferred.promise; 391 return deferred.promise;
345 } 392 }
346 393
347 // Unspecified V8-specific legacy function 394 // Unspecified V8-specific legacy function
348 // Chain is left around for now as an alias for then 395 // Chain is left around for now as an alias for then
349 function PromiseChain(onResolve, onReject) { 396 function PromiseChain(onResolve, onReject) {
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 } 485 }
439 } catch (e) { 486 } catch (e) {
440 deferred.reject(e) 487 deferred.reject(e)
441 } 488 }
442 return deferred.promise; 489 return deferred.promise;
443 } 490 }
444 491
445 492
446 // Utility for debugger 493 // Utility for debugger
447 494
495 function PromiseHasUserDefinedRejectHandlerCheck(handler, deferred) {
496 if (handler !== PromiseIdRejectHandler) {
497 var combinedDeferred = GET_PRIVATE(handler, promiseCombinedDeferredSymbol);
498 if (IS_UNDEFINED(combinedDeferred)) return true;
499 if (PromiseHasUserDefinedRejectHandlerRecursive(combinedDeferred.promise)) {
500 return true;
501 }
502 } else if (PromiseHasUserDefinedRejectHandlerRecursive(deferred.promise)) {
503 return true;
504 }
505 return false;
506 }
507
448 function PromiseHasUserDefinedRejectHandlerRecursive(promise) { 508 function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
449 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol); 509 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol);
510 var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol);
450 if (IS_UNDEFINED(queue)) return false; 511 if (IS_UNDEFINED(queue)) return false;
451 for (var i = 0; i < queue.length; i += 2) { 512 if (!IS_ARRAY(queue)) {
452 var handler = queue[i]; 513 return PromiseHasUserDefinedRejectHandlerCheck(queue, deferreds);
453 if (handler !== PromiseIdRejectHandler) { 514 } else {
454 var deferred = GET_PRIVATE(handler, promiseCombinedDeferredSymbol); 515 for (var i = 0; i < queue.length; i += 1) {
455 if (IS_UNDEFINED(deferred)) return true; 516 if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], deferreds[i])) {
456 if (PromiseHasUserDefinedRejectHandlerRecursive(deferred.promise)) {
457 return true; 517 return true;
458 } 518 }
459 } else if (PromiseHasUserDefinedRejectHandlerRecursive(
460 queue[i + 1].promise)) {
461 return true;
462 } 519 }
463 } 520 }
464 return false; 521 return false;
465 } 522 }
466 523
467 // Return whether the promise will be handled by a user-defined reject 524 // 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 525 // 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. 526 // search for a reject handler that's not the default PromiseIdRejectHandler.
470 function PromiseHasUserDefinedRejectHandler() { 527 function PromiseHasUserDefinedRejectHandler() {
471 return PromiseHasUserDefinedRejectHandlerRecursive(this); 528 return PromiseHasUserDefinedRejectHandlerRecursive(this);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 to.PromiseChain = PromiseChain; 576 to.PromiseChain = PromiseChain;
520 to.PromiseDefer = PromiseDefer; 577 to.PromiseDefer = PromiseDefer;
521 to.PromiseAccept = PromiseAccept; 578 to.PromiseAccept = PromiseAccept;
522 579
523 to.PromiseCreateRejected = PromiseCreateRejected; 580 to.PromiseCreateRejected = PromiseCreateRejected;
524 to.PromiseCreateResolved = PromiseCreateResolved; 581 to.PromiseCreateResolved = PromiseCreateResolved;
525 to.PromiseThen = PromiseThen; 582 to.PromiseThen = PromiseThen;
526 }); 583 });
527 584
528 }) 585 })
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