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

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

Issue 2296703004: Inline CreateResolvingFunctions
Patch Set: update cctest 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 promiseCombinedDeferredSymbol = 15 var promiseCombinedDeferredSymbol =
16 utils.ImportNow("promise_combined_deferred_symbol"); 16 utils.ImportNow("promise_combined_deferred_symbol");
17 var promiseResolvingFunctionCalledSymbol =
18 utils.ImportNow("promise_resolving_function_called_symbol");
17 var promiseHasHandlerSymbol = 19 var promiseHasHandlerSymbol =
18 utils.ImportNow("promise_has_handler_symbol"); 20 utils.ImportNow("promise_has_handler_symbol");
19 var promiseRejectReactionsSymbol = 21 var promiseRejectReactionsSymbol =
20 utils.ImportNow("promise_reject_reactions_symbol"); 22 utils.ImportNow("promise_reject_reactions_symbol");
21 var promiseFulfillReactionsSymbol = 23 var promiseFulfillReactionsSymbol =
22 utils.ImportNow("promise_fulfill_reactions_symbol"); 24 utils.ImportNow("promise_fulfill_reactions_symbol");
23 var promiseDeferredReactionsSymbol = 25 var promiseDeferredReactionsSymbol =
24 utils.ImportNow("promise_deferred_reactions_symbol"); 26 utils.ImportNow("promise_deferred_reactions_symbol");
25 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); 27 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol");
26 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); 28 var promiseStateSymbol = utils.ImportNow("promise_state_symbol");
27 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); 29 var promiseResultSymbol = utils.ImportNow("promise_result_symbol");
28 var SpeciesConstructor; 30 var SpeciesConstructor;
29 var speciesSymbol = utils.ImportNow("species_symbol"); 31 var speciesSymbol = utils.ImportNow("species_symbol");
30 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); 32 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
31 33
32 utils.Import(function(from) { 34 utils.Import(function(from) {
33 SpeciesConstructor = from.SpeciesConstructor; 35 SpeciesConstructor = from.SpeciesConstructor;
34 }); 36 });
35 37
36 // ------------------------------------------------------------------- 38 // -------------------------------------------------------------------
37 39
38 // [[PromiseState]] values: 40 // [[PromiseState]] values:
39 const kPending = 0; 41 const kPending = 0;
40 const kFulfilled = +1; 42 const kFulfilled = +1;
41 const kRejected = -1; 43 const kRejected = -1;
42 44
43 var lastMicrotaskId = 0; 45 var lastMicrotaskId = 0;
44 46
45 // ES#sec-createresolvingfunctions
46 // CreateResolvingFunctions ( promise )
47 function CreateResolvingFunctions(promise, debugEvent) {
Dan Ehrenberg 2016/08/30 22:29:28 The spec calls this in two places, in the promise
48 var alreadyResolved = false;
49
50 // ES#sec-promise-resolve-functions
51 // Promise Resolve Functions
52 var resolve = value => {
53 if (alreadyResolved === true) return;
54 alreadyResolved = true;
55 ResolvePromise(promise, value);
56 };
57
58 // ES#sec-promise-reject-functions
59 // Promise Reject Functions
60 var reject = reason => {
61 if (alreadyResolved === true) return;
62 alreadyResolved = true;
63 RejectPromise(promise, reason, debugEvent);
64 };
65
66 return {
67 __proto__: null,
68 resolve: resolve,
69 reject: reject
70 };
71 }
72
73 47
74 // ES#sec-promise-executor 48 // ES#sec-promise-executor
75 // Promise ( executor ) 49 // Promise ( executor )
76 var GlobalPromise = function Promise(executor) { 50 var GlobalPromise = function Promise(executor) {
77 if (executor === promiseRawSymbol) { 51 if (executor === promiseRawSymbol) {
78 return %_NewObject(GlobalPromise, new.target); 52 return %_NewObject(GlobalPromise, new.target);
79 } 53 }
80 if (IS_UNDEFINED(new.target)) throw %make_type_error(kNotAPromise, this); 54 if (IS_UNDEFINED(new.target)) throw %make_type_error(kNotAPromise, this);
81 if (!IS_CALLABLE(executor)) { 55 if (!IS_CALLABLE(executor)) {
82 throw %make_type_error(kResolverNotAFunction, executor); 56 throw %make_type_error(kResolverNotAFunction, executor);
83 } 57 }
84 58
85 var promise = PromiseInit(%_NewObject(GlobalPromise, new.target)); 59 var promise = PromiseInit(%_NewObject(GlobalPromise, new.target));
86 // Calling the reject function would be a new exception, so debugEvent = true 60 // Calling the reject function would be a new exception, so debugEvent = true
87 var callbacks = CreateResolvingFunctions(promise, true);
88 var debug_is_active = DEBUG_IS_ACTIVE; 61 var debug_is_active = DEBUG_IS_ACTIVE;
62 var reject = reason => RejectPromise(promise, reason, true, true);
Dan Ehrenberg 2016/08/30 22:29:28 I wonder, how is performance if you call Function.
89 try { 63 try {
90 if (debug_is_active) %DebugPushPromise(promise); 64 if (debug_is_active) %DebugPushPromise(promise);
91 executor(callbacks.resolve, callbacks.reject); 65 executor(value => ResolvePromise(promise, value, true),
66 reject);
92 } %catch (e) { // Natives syntax to mark this catch block. 67 } %catch (e) { // Natives syntax to mark this catch block.
93 %_Call(callbacks.reject, UNDEFINED, e); 68 %_Call(reject, UNDEFINED, e);
94 } finally { 69 } finally {
95 if (debug_is_active) %DebugPopPromise(); 70 if (debug_is_active) %DebugPopPromise();
96 } 71 }
97 72
98 return promise; 73 return promise;
99 } 74 }
100 75
101 // Core functionality. 76 // Core functionality.
102 77
103 function PromiseSet(promise, status, value) { 78 function PromiseSet(promise, status, value) {
(...skipping 15 matching lines...) Expand all
119 // There are 2 possible states for this symbol -- 94 // There are 2 possible states for this symbol --
120 // 1) UNDEFINED -- This is the zero state, no deferred object is 95 // 1) UNDEFINED -- This is the zero state, no deferred object is
121 // attached to this symbol. When we want to add a new deferred we 96 // attached to this symbol. When we want to add a new deferred we
122 // directly attach it to this symbol. 97 // directly attach it to this symbol.
123 // 2) symbol with attached deferred object -- New deferred objects 98 // 2) symbol with attached deferred object -- New deferred objects
124 // are not attached to this symbol, but instead they are directly 99 // are not attached to this symbol, but instead they are directly
125 // attached to the resolve, reject callback arrays. At this point, 100 // attached to the resolve, reject callback arrays. At this point,
126 // the deferred symbol's state is stale, and the deferreds should be 101 // the deferred symbol's state is stale, and the deferreds should be
127 // read from the reject, resolve callbacks. 102 // read from the reject, resolve callbacks.
128 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, UNDEFINED); 103 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, UNDEFINED);
104 SET_PRIVATE(promise, promiseResolvingFunctionCalledSymbol, UNDEFINED);
129 105
130 return promise; 106 return promise;
131 } 107 }
132 108
133 function PromiseCreateAndSet(status, value) { 109 function PromiseCreateAndSet(status, value) {
134 var promise = new GlobalPromise(promiseRawSymbol); 110 var promise = new GlobalPromise(promiseRawSymbol);
135 // If debug is active, notify about the newly created promise first. 111 // If debug is active, notify about the newly created promise first.
136 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED); 112 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED);
137 return PromiseSet(promise, status, value); 113 return PromiseSet(promise, status, value);
138 } 114 }
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 function IsPromise(x) { 206 function IsPromise(x) {
231 return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol); 207 return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol);
232 } 208 }
233 209
234 function PromiseCreate() { 210 function PromiseCreate() {
235 return new GlobalPromise(PromiseNopResolver) 211 return new GlobalPromise(PromiseNopResolver)
236 } 212 }
237 213
238 // ES#sec-promise-resolve-functions 214 // ES#sec-promise-resolve-functions
239 // Promise Resolve Functions, steps 6-13 215 // Promise Resolve Functions, steps 6-13
240 function ResolvePromise(promise, resolution) { 216 function ResolvePromise(promise, resolution, follow) {
217 var status = GET_PRIVATE(promise, promiseResolvingFunctionCalledSymbol);
218 if (!IS_UNDEFINED(status) && follow) return;
219
241 if (resolution === promise) { 220 if (resolution === promise) {
242 return RejectPromise(promise, 221 return RejectPromise(promise,
243 %make_type_error(kPromiseCyclic, resolution), 222 %make_type_error(kPromiseCyclic, resolution),
244 true); 223 true);
245 } 224 }
225
246 if (IS_RECEIVER(resolution)) { 226 if (IS_RECEIVER(resolution)) {
247 // 25.4.1.3.2 steps 8-12 227 // 25.4.1.3.2 steps 8-12
248 try { 228 try {
249 var then = resolution.then; 229 var then = resolution.then;
250 } catch (e) { 230 } catch (e) {
251 return RejectPromise(promise, e, true); 231 return RejectPromise(promise, e, true);
252 } 232 }
253 233
254 // Resolution is a native promise and if it's already resolved or 234 // Resolution is a native promise and if it's already resolved or
255 // rejected, shortcircuit the resolution procedure by directly 235 // rejected, shortcircuit the resolution procedure by directly
(...skipping 20 matching lines...) Expand all
276 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); 256 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true);
277 return; 257 return;
278 } 258 }
279 } 259 }
280 260
281 if (IS_CALLABLE(then)) { 261 if (IS_CALLABLE(then)) {
282 // PromiseResolveThenableJob 262 // PromiseResolveThenableJob
283 var id; 263 var id;
284 var name = "PromiseResolveThenableJob"; 264 var name = "PromiseResolveThenableJob";
285 var instrumenting = DEBUG_IS_ACTIVE; 265 var instrumenting = DEBUG_IS_ACTIVE;
266 SET_PRIVATE(promise, promiseResolvingFunctionCalledSymbol, true);
267
286 %EnqueueMicrotask(function() { 268 %EnqueueMicrotask(function() {
287 if (instrumenting) { 269 if (instrumenting) {
288 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); 270 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
289 } 271 }
290 // These resolving functions simply forward the exception, so 272 // These resolving functions simply forward the exception, so
291 // don't create a new debugEvent. 273 // don't create a new debugEvent.
292 var callbacks = CreateResolvingFunctions(promise, false); 274
293 try { 275 try {
294 %_Call(then, resolution, callbacks.resolve, callbacks.reject); 276 %_Call(then, resolution,
277 value => ResolvePromise(promise, value, false),
278 reason => RejectPromise(promise, reason, false, false));
295 } catch (e) { 279 } catch (e) {
296 %_Call(callbacks.reject, UNDEFINED, e); 280 %_Call(reason => RejectPromise(promise, reason, false, true), UNDEFINE D, e);
297 } 281 }
298 if (instrumenting) { 282 if (instrumenting) {
299 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); 283 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
300 } 284 }
301 }); 285 });
302 if (instrumenting) { 286 if (instrumenting) {
303 id = ++lastMicrotaskId; 287 id = ++lastMicrotaskId;
304 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); 288 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
305 } 289 }
306 return; 290 return;
307 } 291 }
308 } 292 }
309 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ; 293 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ;
310 } 294 }
311 295
312 // ES#sec-rejectpromise 296 // ES#sec-rejectpromise
313 // RejectPromise ( promise, reason ) 297 // RejectPromise ( promise, reason )
314 function RejectPromise(promise, reason, debugEvent) { 298 function RejectPromise(promise, reason, debugEvent, follow) {
Dan Ehrenberg 2016/08/30 22:29:28 I know I made things bad with the debugEvent param
299 var status = GET_PRIVATE(promise, promiseResolvingFunctionCalledSymbol);
300 if (!IS_UNDEFINED(status) && follow) return;
301
302 status = GET_PRIVATE(promise, promiseStateSymbol);
303 if (status === kFulfilled) return;
adamk 2016/08/30 23:00:35 This looks like an unrelated bit of inlining, cons
315 // Check promise status to confirm that this reject has an effect. 304 // Check promise status to confirm that this reject has an effect.
316 // Call runtime for callbacks to the debugger or for unhandled reject. 305 // Call runtime for callbacks to the debugger or for unhandled reject.
317 // The debugEvent parameter sets whether a debug ExceptionEvent should 306 // The debugEvent parameter sets whether a debug ExceptionEvent should
318 // be triggered. It should be set to false when forwarding a rejection 307 // be triggered. It should be set to false when forwarding a rejection
319 // rather than creating a new one. 308 // rather than creating a new one.
320 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { 309 if (status === kPending) {
321 // This check is redundant with checks in the runtime, but it may help 310 // This check is redundant with checks in the runtime, but it may help
322 // avoid unnecessary runtime calls. 311 // avoid unnecessary runtime calls.
323 if ((debugEvent && DEBUG_IS_ACTIVE) || 312 if ((debugEvent && DEBUG_IS_ACTIVE) ||
324 !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { 313 !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) {
325 %PromiseRejectEvent(promise, reason, debugEvent); 314 %PromiseRejectEvent(promise, reason, debugEvent);
326 } 315 }
327 } 316 }
317
328 FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol) 318 FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol)
329 } 319 }
330 320
331 // Export to bindings 321 // Export to bindings
332 function DoRejectPromise(promise, reason) { 322 function DoRejectPromise(promise, reason) {
333 return RejectPromise(promise, reason, true); 323 return RejectPromise(promise, reason, true);
334 } 324 }
335 325
336 // ES#sec-newpromisecapability 326 // ES#sec-newpromisecapability
337 // NewPromiseCapability ( C ) 327 // NewPromiseCapability ( C )
338 function NewPromiseCapability(C, debugEvent) { 328 function NewPromiseCapability(C, debugEvent) {
339 if (C === GlobalPromise) { 329 if (C === GlobalPromise) {
340 // Optimized case, avoid extra closure. 330 // Optimized case, avoid extra closure.
341 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); 331 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol));
342 var callbacks = CreateResolvingFunctions(promise, debugEvent);
343 return { 332 return {
344 promise: promise, 333 promise: promise,
345 resolve: callbacks.resolve, 334 resolve: value => ResolvePromise(promise, value, true),
346 reject: callbacks.reject 335 reject: reason => RejectPromise(promise, reason, debugEvent, true)
347 }; 336 };
348 } 337 }
349 338
350 var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED }; 339 var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED };
351 result.promise = new C((resolve, reject) => { 340 result.promise = new C((resolve, reject) => {
352 if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject)) 341 if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject))
353 throw %make_type_error(kPromiseExecutorAlreadyInvoked); 342 throw %make_type_error(kPromiseExecutorAlreadyInvoked);
354 result.resolve = resolve; 343 result.resolve = resolve;
355 result.reject = reject; 344 result.reject = reject;
356 }); 345 });
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 to.PromiseCastResolved = PromiseCastResolved; 615 to.PromiseCastResolved = PromiseCastResolved;
627 to.PromiseThen = PromiseThen; 616 to.PromiseThen = PromiseThen;
628 617
629 to.GlobalPromise = GlobalPromise; 618 to.GlobalPromise = GlobalPromise;
630 to.NewPromiseCapability = NewPromiseCapability; 619 to.NewPromiseCapability = NewPromiseCapability;
631 to.PerformPromiseThen = PerformPromiseThen; 620 to.PerformPromiseThen = PerformPromiseThen;
632 to.RejectPromise = RejectPromise; 621 to.RejectPromise = RejectPromise;
633 }); 622 });
634 623
635 }) 624 })
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698