OLD | NEW |
---|---|
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 |
(...skipping 26 matching lines...) Expand all Loading... | |
37 | 37 |
38 // [[PromiseState]] values: | 38 // [[PromiseState]] values: |
39 const kPending = 0; | 39 const kPending = 0; |
40 const kFulfilled = +1; | 40 const kFulfilled = +1; |
41 const kRejected = -1; | 41 const kRejected = -1; |
42 | 42 |
43 var lastMicrotaskId = 0; | 43 var lastMicrotaskId = 0; |
44 | 44 |
45 // ES#sec-createresolvingfunctions | 45 // ES#sec-createresolvingfunctions |
46 // CreateResolvingFunctions ( promise ) | 46 // CreateResolvingFunctions ( promise ) |
47 function CreateResolvingFunctions(promise) { | 47 function CreateResolvingFunctions(promise, suppressDebugEvent) { |
48 var alreadyResolved = false; | 48 var alreadyResolved = false; |
49 | 49 |
50 // ES#sec-promise-resolve-functions | 50 // ES#sec-promise-resolve-functions |
51 // Promise Resolve Functions | 51 // Promise Resolve Functions |
52 var resolve = value => { | 52 var resolve = value => { |
53 if (alreadyResolved === true) return; | 53 if (alreadyResolved === true) return; |
54 alreadyResolved = true; | 54 alreadyResolved = true; |
55 ResolvePromise(promise, value); | 55 ResolvePromise(promise, value); |
56 }; | 56 }; |
57 | 57 |
58 // ES#sec-promise-reject-functions | 58 // ES#sec-promise-reject-functions |
59 // Promise Reject Functions | 59 // Promise Reject Functions |
60 var reject = reason => { | 60 var reject = reason => { |
61 if (alreadyResolved === true) return; | 61 if (alreadyResolved === true) return; |
62 alreadyResolved = true; | 62 alreadyResolved = true; |
63 RejectPromise(promise, reason); | 63 RejectPromise(promise, reason, suppressDebugEvent); |
64 }; | 64 }; |
65 | 65 |
66 return { | 66 return { |
67 __proto__: null, | 67 __proto__: null, |
68 resolve: resolve, | 68 resolve: resolve, |
69 reject: reject | 69 reject: reject |
70 }; | 70 }; |
71 } | 71 } |
72 | 72 |
73 | 73 |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
261 promiseFulfillReactionsSymbol); | 261 promiseFulfillReactionsSymbol); |
262 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); | 262 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); |
263 return; | 263 return; |
264 } else if (thenableState === kRejected) { | 264 } else if (thenableState === kRejected) { |
265 var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol); | 265 var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol); |
266 if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) { | 266 if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) { |
267 // Promise has already been rejected, but had no handler. | 267 // Promise has already been rejected, but had no handler. |
268 // Revoke previously triggered reject event. | 268 // Revoke previously triggered reject event. |
269 %PromiseRevokeReject(resolution); | 269 %PromiseRevokeReject(resolution); |
270 } | 270 } |
271 RejectPromise(promise, thenableValue); | 271 RejectPromise(promise, thenableValue, true); |
272 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); | 272 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); |
273 return; | 273 return; |
274 } | 274 } |
275 } | 275 } |
276 | 276 |
277 if (IS_CALLABLE(then)) { | 277 if (IS_CALLABLE(then)) { |
278 // PromiseResolveThenableJob | 278 // PromiseResolveThenableJob |
279 var id; | 279 var id; |
280 var name = "PromiseResolveThenableJob"; | 280 var name = "PromiseResolveThenableJob"; |
281 var instrumenting = DEBUG_IS_ACTIVE; | 281 var instrumenting = DEBUG_IS_ACTIVE; |
282 %EnqueueMicrotask(function() { | 282 %EnqueueMicrotask(function() { |
283 if (instrumenting) { | 283 if (instrumenting) { |
284 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); | 284 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); |
285 } | 285 } |
286 var callbacks = CreateResolvingFunctions(promise); | 286 var callbacks = CreateResolvingFunctions(promise, true); |
287 try { | 287 try { |
288 %_Call(then, resolution, callbacks.resolve, callbacks.reject); | 288 %_Call(then, resolution, callbacks.resolve, callbacks.reject); |
289 } catch (e) { | 289 } catch (e) { |
290 %_Call(callbacks.reject, UNDEFINED, e); | 290 %_Call(callbacks.reject, UNDEFINED, e); |
291 } | 291 } |
292 if (instrumenting) { | 292 if (instrumenting) { |
293 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); | 293 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); |
294 } | 294 } |
295 }); | 295 }); |
296 if (instrumenting) { | 296 if (instrumenting) { |
297 id = ++lastMicrotaskId; | 297 id = ++lastMicrotaskId; |
298 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); | 298 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); |
299 } | 299 } |
300 return; | 300 return; |
301 } | 301 } |
302 } | 302 } |
303 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ; | 303 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ; |
304 } | 304 } |
305 | 305 |
306 // ES#sec-rejectpromise | 306 // ES#sec-rejectpromise |
307 // RejectPromise ( promise, reason ) | 307 // RejectPromise ( promise, reason ) |
308 function RejectPromise(promise, reason) { | 308 function RejectPromise(promise, reason, suppressDebugEvent) { |
adamk
2016/08/23 22:29:27
It's confusing to me that %PromiseRejectEvent take
Dan Ehrenberg
2016/08/23 23:28:38
Good point. Switched it to debugEvent as a positiv
| |
309 // Check promise status to confirm that this reject has an effect. | 309 // Check promise status to confirm that this reject has an effect. |
310 // Call runtime for callbacks to the debugger or for unhandled reject. | 310 // Call runtime for callbacks to the debugger or for unhandled reject. |
311 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { | 311 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { |
312 var debug_is_active = DEBUG_IS_ACTIVE; | 312 var debugEvent = DEBUG_IS_ACTIVE && !suppressDebugEvent |
313 if (debug_is_active || | 313 if (debugEvent || |
314 !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { | 314 !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { |
315 %PromiseRejectEvent(promise, reason, debug_is_active); | 315 %PromiseRejectEvent(promise, reason, debugEvent, false); |
316 } | 316 } |
317 } | 317 } |
318 FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol) | 318 FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol) |
319 } | 319 } |
320 | 320 |
321 // ES#sec-newpromisecapability | 321 // ES#sec-newpromisecapability |
322 // NewPromiseCapability ( C ) | 322 // NewPromiseCapability ( C ) |
323 function NewPromiseCapability(C) { | 323 function NewPromiseCapability(C, suppressDebugEvent) { |
324 if (C === GlobalPromise) { | 324 if (C === GlobalPromise) { |
325 // Optimized case, avoid extra closure. | 325 // Optimized case, avoid extra closure. |
326 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); | 326 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); |
327 var callbacks = CreateResolvingFunctions(promise); | 327 var callbacks = CreateResolvingFunctions(promise, suppressDebugEvent); |
328 return { | 328 return { |
329 promise: promise, | 329 promise: promise, |
330 resolve: callbacks.resolve, | 330 resolve: callbacks.resolve, |
331 reject: callbacks.reject | 331 reject: callbacks.reject |
332 }; | 332 }; |
333 } | 333 } |
334 | 334 |
335 var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED }; | 335 var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED }; |
336 result.promise = new C((resolve, reject) => { | 336 result.promise = new C((resolve, reject) => { |
337 if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject)) | 337 if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject)) |
(...skipping 10 matching lines...) Expand all Loading... | |
348 | 348 |
349 // ES#sec-promise.reject | 349 // ES#sec-promise.reject |
350 // Promise.reject ( x ) | 350 // Promise.reject ( x ) |
351 function PromiseReject(r) { | 351 function PromiseReject(r) { |
352 if (!IS_RECEIVER(this)) { | 352 if (!IS_RECEIVER(this)) { |
353 throw %make_type_error(kCalledOnNonObject, PromiseResolve); | 353 throw %make_type_error(kCalledOnNonObject, PromiseResolve); |
354 } | 354 } |
355 if (this === GlobalPromise) { | 355 if (this === GlobalPromise) { |
356 // Optimized case, avoid extra closure. | 356 // Optimized case, avoid extra closure. |
357 var promise = PromiseCreateAndSet(kRejected, r); | 357 var promise = PromiseCreateAndSet(kRejected, r); |
358 // The debug event for this would always be an uncaught promise reject, | 358 // Trigger debug events if the debugger is on, as Promise.reject is |
359 // which is usually simply noise. Do not trigger that debug event. | 359 // equivalent to throwing an exception directly. |
360 %PromiseRejectEvent(promise, r, false); | 360 %PromiseRejectEvent(promise, r, DEBUG_IS_ACTIVE, true); |
361 return promise; | 361 return promise; |
362 } else { | 362 } else { |
363 var promiseCapability = NewPromiseCapability(this); | 363 var promiseCapability = NewPromiseCapability(this); |
364 %_Call(promiseCapability.reject, UNDEFINED, r); | 364 %_Call(promiseCapability.reject, UNDEFINED, r); |
365 return promiseCapability.promise; | 365 return promiseCapability.promise; |
366 } | 366 } |
367 } | 367 } |
368 | 368 |
369 // Shortcut Promise.reject and Promise.resolve() implementations, used by | 369 // Shortcut Promise.reject and Promise.resolve() implementations, used by |
370 // Async Functions implementation. | 370 // Async Functions implementation. |
371 function PromiseCreateRejected(r) { | 371 function PromiseCreateRejected(r) { |
372 return %_Call(PromiseReject, GlobalPromise, r); | 372 var promise = PromiseCreateAndSet(kRejected, r); |
373 // This is called from the desugaring of async/await; no reason to | |
374 // create a redundant reject event. | |
375 %PromiseRejectEvent(promise, r, false, false); | |
adamk
2016/08/23 22:29:27
Passing two bools is not ideal, see suggestion in
Dan Ehrenberg
2016/08/23 23:28:38
Fixed, now separated out a different function.
| |
376 return promise; | |
373 } | 377 } |
374 | 378 |
375 function PromiseCreateResolved(value) { | 379 function PromiseCreateResolved(value) { |
376 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); | 380 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); |
377 var resolveResult = ResolvePromise(promise, value); | 381 var resolveResult = ResolvePromise(promise, value); |
378 return promise; | 382 return promise; |
379 } | 383 } |
380 | 384 |
381 function PromiseCastResolved(value) { | 385 function PromiseCastResolved(value) { |
382 if (IsPromise(value)) { | 386 if (IsPromise(value)) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 // ES#sec-promise.prototype.then | 424 // ES#sec-promise.prototype.then |
421 // Promise.prototype.then ( onFulfilled, onRejected ) | 425 // Promise.prototype.then ( onFulfilled, onRejected ) |
422 // Multi-unwrapped chaining with thenable coercion. | 426 // Multi-unwrapped chaining with thenable coercion. |
423 function PromiseThen(onResolve, onReject) { | 427 function PromiseThen(onResolve, onReject) { |
424 var status = GET_PRIVATE(this, promiseStateSymbol); | 428 var status = GET_PRIVATE(this, promiseStateSymbol); |
425 if (IS_UNDEFINED(status)) { | 429 if (IS_UNDEFINED(status)) { |
426 throw %make_type_error(kNotAPromise, this); | 430 throw %make_type_error(kNotAPromise, this); |
427 } | 431 } |
428 | 432 |
429 var constructor = SpeciesConstructor(this, GlobalPromise); | 433 var constructor = SpeciesConstructor(this, GlobalPromise); |
430 var resultCapability = NewPromiseCapability(constructor); | 434 var resultCapability = NewPromiseCapability(constructor, true); |
431 return PerformPromiseThen(this, onResolve, onReject, resultCapability); | 435 return PerformPromiseThen(this, onResolve, onReject, resultCapability); |
432 } | 436 } |
433 | 437 |
434 // ES#sec-promise.prototype.catch | 438 // ES#sec-promise.prototype.catch |
435 // Promise.prototype.catch ( onRejected ) | 439 // Promise.prototype.catch ( onRejected ) |
436 function PromiseCatch(onReject) { | 440 function PromiseCatch(onReject) { |
437 return this.then(UNDEFINED, onReject); | 441 return this.then(UNDEFINED, onReject); |
438 } | 442 } |
439 | 443 |
440 // Combinators. | 444 // Combinators. |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
617 utils.Export(function(to) { | 621 utils.Export(function(to) { |
618 to.PromiseCastResolved = PromiseCastResolved; | 622 to.PromiseCastResolved = PromiseCastResolved; |
619 to.PromiseThen = PromiseThen; | 623 to.PromiseThen = PromiseThen; |
620 | 624 |
621 to.GlobalPromise = GlobalPromise; | 625 to.GlobalPromise = GlobalPromise; |
622 to.NewPromiseCapability = NewPromiseCapability; | 626 to.NewPromiseCapability = NewPromiseCapability; |
623 to.PerformPromiseThen = PerformPromiseThen; | 627 to.PerformPromiseThen = PerformPromiseThen; |
624 }); | 628 }); |
625 | 629 |
626 }) | 630 }) |
OLD | NEW |