| Index: src/promise.js
|
| diff --git a/src/promise.js b/src/promise.js
|
| index e402a18532647b96b6b07268858f95c4aa627064..350eef4eb8e6ca583f5a95ecd44a6e2c55a19f77 100644
|
| --- a/src/promise.js
|
| +++ b/src/promise.js
|
| @@ -18,7 +18,9 @@ var PromiseReject;
|
| var PromiseChain;
|
| var PromiseCatch;
|
| var PromiseThen;
|
| -var PromiseHasRejectHandler;
|
| +var PromiseScheduleUnhandledRejectMessage;
|
| +var PromiseScheduleRevokeRejectMessage;
|
| +var PromiseDispatchUnhandledRejectMessages;
|
| var PromiseHasUserDefinedRejectHandler;
|
|
|
| // mirror-debugger.js currently uses builtins.promiseStatus. It would be nice
|
| @@ -31,8 +33,12 @@ var promiseValue = GLOBAL_PRIVATE("Promise#value");
|
| var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve");
|
| var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject");
|
| var promiseRaw = GLOBAL_PRIVATE("Promise#raw");
|
| -var promiseHasHandler = %PromiseHasHandlerSymbol();
|
| +var promiseHasHandler = GLOBAL_PRIVATE("Promise#hasHandler");
|
| +// Enqueued promise message: true = revoke reject, false = unhandled reject
|
| +var promiseMessage = GLOBAL_PRIVATE("Promise#message");
|
| var lastMicrotaskId = 0;
|
| +var promiseMicrotasksCount = 0;
|
| +var enqueuedPromiseMessages;
|
|
|
|
|
| (function() {
|
| @@ -119,16 +125,18 @@ var lastMicrotaskId = 0;
|
|
|
| function PromiseEnqueue(value, tasks, status) {
|
| var id, name, instrumenting = DEBUG_IS_ACTIVE;
|
| + ++promiseMicrotasksCount;
|
| %EnqueueMicrotask(function() {
|
| if (instrumenting) {
|
| %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
|
| }
|
| for (var i = 0; i < tasks.length; i += 2) {
|
| - PromiseHandle(value, tasks[i], tasks[i + 1])
|
| + PromiseHandle(value, tasks[i], tasks[i + 1]);
|
| }
|
| if (instrumenting) {
|
| %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
|
| }
|
| + --promiseMicrotasksCount;
|
| });
|
| if (instrumenting) {
|
| id = ++lastMicrotaskId;
|
| @@ -163,9 +171,11 @@ var lastMicrotaskId = 0;
|
| // Check promise status to confirm that this reject has an effect.
|
| // Call runtime for callbacks to the debugger or for unhandled reject.
|
| if (GET_PRIVATE(promise, promiseStatus) == 0) {
|
| - var debug_is_active = DEBUG_IS_ACTIVE;
|
| - if (debug_is_active || !HAS_DEFINED_PRIVATE(promise, promiseHasHandler)) {
|
| - %PromiseRejectEvent(promise, r, debug_is_active);
|
| + if (DEBUG_IS_ACTIVE) {
|
| + %DebugPromiseRejectEvent(promise, r);
|
| + }
|
| + if (!HAS_DEFINED_PRIVATE(promise, promiseHasHandler)) {
|
| + PromiseScheduleUnhandledRejectMessage(promise, r, false);
|
| }
|
| }
|
| PromiseDone(promise, -1, r, promiseOnReject)
|
| @@ -206,9 +216,7 @@ var lastMicrotaskId = 0;
|
| if (this === $Promise) {
|
| // Optimized case, avoid extra closure.
|
| promise = PromiseSet(new $Promise(promiseRaw), -1, 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);
|
| + PromiseScheduleUnhandledRejectMessage(promise, r, false);
|
| } else {
|
| promise = new this(function(resolve, reject) { reject(r) });
|
| }
|
| @@ -237,8 +245,8 @@ var lastMicrotaskId = 0;
|
| case -1: // Rejected
|
| if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
|
| // Promise has already been rejected, but had no handler.
|
| - // Revoke previously triggered reject event.
|
| - %PromiseRevokeReject(this);
|
| + // Revoke previously triggered reject message.
|
| + PromiseScheduleRevokeRejectMessage(this);
|
| }
|
| PromiseEnqueue(GET_PRIVATE(this, promiseValue),
|
| [onReject, deferred],
|
| @@ -340,6 +348,41 @@ var lastMicrotaskId = 0;
|
|
|
| // Utility for debugger
|
|
|
| + function PromiseScheduleUnhandledRejectMessage(promise, r, revoke) {
|
| + if (!enqueuedPromiseMessages) {
|
| + enqueuedPromiseMessages = new InternalArray;
|
| + %EnqueueMicrotask(PromiseDispatchUnhandledRejectMessages);
|
| + }
|
| + SET_PRIVATE(promise, promiseMessage, revoke);
|
| + enqueuedPromiseMessages.push(promise, r);
|
| + }
|
| +
|
| + function PromiseScheduleRevokeRejectMessage(promise) {
|
| + if (HAS_DEFINED_PRIVATE(promise, promiseMessage)) {
|
| + DELETE_PRIVATE(promise, promiseMessage);
|
| + } else {
|
| + PromiseScheduleUnhandledRejectMessage(promise, UNDEFINED, true);
|
| + }
|
| + }
|
| +
|
| + function PromiseDispatchUnhandledRejectMessages() {
|
| + if (promiseMicrotasksCount || %PendingMicrotaskCount()) {
|
| + %EnqueueMicrotask(PromiseDispatchUnhandledRejectMessages);
|
| + return;
|
| + }
|
| + var queue = enqueuedPromiseMessages;
|
| + enqueuedPromiseMessages = UNDEFINED;
|
| + for (var i = 0; i < queue.length; i += 2) {
|
| + var promise = queue[i];
|
| + if (HAS_DEFINED_PRIVATE(promise, promiseMessage)) {
|
| + var revoke = GET_PRIVATE(promise, promiseMessage);
|
| + DELETE_PRIVATE(promise, promiseMessage);
|
| + if (revoke) %PromiseRevokeRejectMessage(promise);
|
| + else %PromiseRejectMessage(promise, queue[i + 1]);
|
| + }
|
| + }
|
| + }
|
| +
|
| function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
|
| var queue = GET_PRIVATE(promise, promiseOnReject);
|
| if (IS_UNDEFINED(queue)) return false;
|
|
|