Chromium Code Reviews| Index: src/js/promise.js |
| diff --git a/src/js/promise.js b/src/js/promise.js |
| index b50fc80b305bdcfd509e479cfb703171b85eac9b..cb88f46e5e7523dfb6db9e50146acb0edaf63090 100644 |
| --- a/src/js/promise.js |
| +++ b/src/js/promise.js |
| @@ -44,7 +44,7 @@ var lastMicrotaskId = 0; |
| // ES#sec-createresolvingfunctions |
| // CreateResolvingFunctions ( promise ) |
| -function CreateResolvingFunctions(promise) { |
| +function CreateResolvingFunctions(promise, debugEvent) { |
| var alreadyResolved = false; |
| // ES#sec-promise-resolve-functions |
| @@ -60,7 +60,7 @@ function CreateResolvingFunctions(promise) { |
| var reject = reason => { |
| if (alreadyResolved === true) return; |
| alreadyResolved = true; |
| - RejectPromise(promise, reason); |
| + RejectPromise(promise, reason, debugEvent); |
| }; |
| return { |
| @@ -83,7 +83,8 @@ var GlobalPromise = function Promise(executor) { |
| } |
| var promise = PromiseInit(%_NewObject(GlobalPromise, new.target)); |
| - var callbacks = CreateResolvingFunctions(promise); |
| + // Calling the reject function would be a new exception, so debugEvent = true |
| + var callbacks = CreateResolvingFunctions(promise, true); |
| var debug_is_active = DEBUG_IS_ACTIVE; |
| try { |
| if (debug_is_active) %DebugPushPromise(promise); |
| @@ -238,14 +239,16 @@ function PromiseCreate() { |
| // Promise Resolve Functions, steps 6-13 |
| function ResolvePromise(promise, resolution) { |
| if (resolution === promise) { |
| - return RejectPromise(promise, %make_type_error(kPromiseCyclic, resolution)); |
| + return RejectPromise(promise, |
| + %make_type_error(kPromiseCyclic, resolution), |
| + true); |
| } |
| if (IS_RECEIVER(resolution)) { |
| // 25.4.1.3.2 steps 8-12 |
| try { |
| var then = resolution.then; |
| } catch (e) { |
| - return RejectPromise(promise, e); |
| + return RejectPromise(promise, e, true); |
| } |
| // Resolution is a native promise and if it's already resolved or |
| @@ -268,7 +271,8 @@ function ResolvePromise(promise, resolution) { |
| // Revoke previously triggered reject event. |
| %PromiseRevokeReject(resolution); |
| } |
| - RejectPromise(promise, thenableValue); |
| + // Don't cause a debug event as this case is forwarding a rejection |
| + RejectPromise(promise, thenableValue, false); |
| SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); |
| return; |
| } |
| @@ -283,7 +287,9 @@ function ResolvePromise(promise, resolution) { |
| if (instrumenting) { |
| %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); |
| } |
| - var callbacks = CreateResolvingFunctions(promise); |
| + // These resolving functions simply forward the exception, so |
| + // don't create a new debugEvent. |
| + var callbacks = CreateResolvingFunctions(promise, false); |
| try { |
| %_Call(then, resolution, callbacks.resolve, callbacks.reject); |
| } catch (e) { |
| @@ -304,27 +310,36 @@ function ResolvePromise(promise, resolution) { |
| } |
| // ES#sec-rejectpromise |
| -// RejectPromise ( promise, reason ) |
| -function RejectPromise(promise, reason) { |
| +// RejectPromise ( promise, reason )o |
|
adamk
2016/08/23 23:43:38
Stray edit? vi user?
|
| +function RejectPromise(promise, reason, debugEvent) { |
| // Check promise status to confirm that this reject has an effect. |
| // Call runtime for callbacks to the debugger or for unhandled reject. |
| + // The debugEvent parameter sets whether a debug ExceptionEvent should |
| + // be triggered. It should be set to false when forwarding a rejection |
| + // rather than creating a new one. |
| if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { |
| - var debug_is_active = DEBUG_IS_ACTIVE; |
| - if (debug_is_active || |
| + // This check is redundant with checks in the runtime, but it may help |
| + // avoid unnecessary runtime calls. |
| + if ((debugEvent && DEBUG_IS_ACTIVE)|| |
|
adamk
2016/08/23 23:43:38
Nit: please add a space between ")" and "||"
|
| !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { |
| - %PromiseRejectEvent(promise, reason, debug_is_active); |
| + %PromiseRejectEvent(promise, reason, debugEvent); |
| } |
| } |
| FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol) |
| } |
| +// Export to bindings |
| +function DoRejectPromise(promise, reason) { |
| + return RejectPromise(promise, reason, true); |
| +} |
| + |
| // ES#sec-newpromisecapability |
| // NewPromiseCapability ( C ) |
| -function NewPromiseCapability(C) { |
| +function NewPromiseCapability(C, debugEvent) { |
| if (C === GlobalPromise) { |
| // Optimized case, avoid extra closure. |
| var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); |
| - var callbacks = CreateResolvingFunctions(promise); |
| + var callbacks = CreateResolvingFunctions(promise, debugEvent); |
| return { |
| promise: promise, |
| resolve: callbacks.resolve, |
| @@ -355,12 +370,12 @@ function PromiseReject(r) { |
| if (this === GlobalPromise) { |
| // Optimized case, avoid extra closure. |
| var promise = PromiseCreateAndSet(kRejected, r); |
| - // The debug event for this would always be an uncaught promise reject, |
| - // which is usually simply noise. Do not trigger that debug event. |
| - %PromiseRejectEvent(promise, r, false); |
| + // Trigger debug events if the debugger is on, as Promise.reject is |
| + // equivalent to throwing an exception directly. |
| + %PromiseRejectEventFromStack(promise, r); |
| return promise; |
| } else { |
| - var promiseCapability = NewPromiseCapability(this); |
| + var promiseCapability = NewPromiseCapability(this, true); |
| %_Call(promiseCapability.reject, UNDEFINED, r); |
| return promiseCapability.promise; |
| } |
| @@ -369,7 +384,11 @@ function PromiseReject(r) { |
| // Shortcut Promise.reject and Promise.resolve() implementations, used by |
| // Async Functions implementation. |
| function PromiseCreateRejected(r) { |
| - return %_Call(PromiseReject, GlobalPromise, r); |
| + var promise = PromiseCreateAndSet(kRejected, r); |
| + // This is called from the desugaring of async/await; no reason to |
| + // create a redundant reject event. |
| + %PromiseRejectEvent(promise, r, false); |
| + return promise; |
| } |
| function PromiseCreateResolved(value) { |
| @@ -427,7 +446,9 @@ function PromiseThen(onResolve, onReject) { |
| } |
| var constructor = SpeciesConstructor(this, GlobalPromise); |
| - var resultCapability = NewPromiseCapability(constructor); |
| + // Pass false for debugEvent so .then chaining does not trigger |
| + // redundant ExceptionEvents. |
| + var resultCapability = NewPromiseCapability(constructor, false); |
| return PerformPromiseThen(this, onResolve, onReject, resultCapability); |
| } |
| @@ -454,7 +475,8 @@ function PromiseResolve(x) { |
| return promise; |
| } |
| - var promiseCapability = NewPromiseCapability(this); |
| + // debugEvent is not so meaningful here as it will be resolved |
| + var promiseCapability = NewPromiseCapability(this, true); |
| var resolveResult = %_Call(promiseCapability.resolve, UNDEFINED, x); |
| return promiseCapability.promise; |
| } |
| @@ -466,7 +488,9 @@ function PromiseAll(iterable) { |
| throw %make_type_error(kCalledOnNonObject, "Promise.all"); |
| } |
| - var deferred = NewPromiseCapability(this); |
| + // false debugEvent so that forwarding the rejection through all does not |
| + // trigger redundant ExceptionEvents |
| + var deferred = NewPromiseCapability(this, false); |
| var resolutions = new InternalArray(); |
| var count; |
| @@ -517,7 +541,9 @@ function PromiseRace(iterable) { |
| throw %make_type_error(kCalledOnNonObject, PromiseRace); |
| } |
| - var deferred = NewPromiseCapability(this); |
| + // false debugEvent so that forwarding the rejection through race does not |
| + // trigger redundant ExceptionEvents |
| + var deferred = NewPromiseCapability(this, false); |
| try { |
| for (var value of iterable) { |
| this.resolve(value).then(deferred.resolve, deferred.reject); |
| @@ -598,7 +624,7 @@ utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [ |
| "promise_catch", PromiseCatch, |
| "promise_create", PromiseCreate, |
| "promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler, |
| - "promise_reject", RejectPromise, |
| + "promise_reject", DoRejectPromise, |
| "promise_resolve", ResolvePromise, |
| "promise_then", PromiseThen, |
| "promise_create_rejected", PromiseCreateRejected, |
| @@ -611,7 +637,7 @@ utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [ |
| utils.InstallFunctions(extrasUtils, 0, [ |
| "createPromise", PromiseCreate, |
| "resolvePromise", ResolvePromise, |
| - "rejectPromise", RejectPromise |
| + "rejectPromise", DoRejectPromise |
| ]); |
| utils.Export(function(to) { |