diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index ffb778696e..8447a97881 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -2299,8 +2299,25 @@ RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue res return Call(cx, calleeOrRval, UndefinedHandleValue, result, &calleeOrRval); } - if (!promiseObj) + if (!promiseObj) { + if (mode == RejectMode) { + // The rejection will never be handled, given the returned promise + // is known to be unused, and already optimized away. + // + // Create temporary Promise object and reject it, in order to + // report the unhandled rejection. + // + // Allocation time points wrong time, but won't matter much. + Rooted temporaryPromise(cx); + temporaryPromise = CreatePromiseObjectWithoutResolutionFunctions(cx); + if (!temporaryPromise) { + cx->clearPendingException(); + return true; + } + return RejectPromiseInternal(cx, temporaryPromise, result); + } return true; + } Handle promise = promiseObj.as(); if (promise->state() != JS::PromiseState::Pending) diff --git a/js/src/tests/non262/Promise/promise-rejection-tracking-optimized.js b/js/src/tests/non262/Promise/promise-rejection-tracking-optimized.js new file mode 100644 index 0000000000..c085b9dba8 --- /dev/null +++ b/js/src/tests/non262/Promise/promise-rejection-tracking-optimized.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs setPromiseRejectionTrackerCallback + +const UNHANDLED = 0; +const HANDLED = 1; + +let rejections = new Map(); +function rejectionTracker(promise, state) { + rejections.set(promise, state); +} +setPromiseRejectionTrackerCallback(rejectionTracker); + +// If the return value of then is not used, the promise object is optimized +// away, but if a rejection happens, the rejection should be notified. +Promise.resolve().then(() => { throw 1; }); +drainJobQueue(); + +assertEq(rejections.size, 1); + +let [[promise, state]] = rejections; +assertEq(state, UNHANDLED); + +let exc; +promise.catch(x => { exc = x; }); +drainJobQueue(); + +// we handled it after all +assertEq(rejections.get(promise), HANDLED); + +// the right exception was reported +assertEq(exc, 1); + +if (this.reportCompare) { + reportCompare(true,true); +}