| 128 | } |
| 129 | |
| 130 | void JobQueue::promiseRejectionTracker(JSContext *cx, |
| 131 | bool mutedErrors, |
| 132 | JS::HandleObject promise, |
| 133 | JS::PromiseRejectionHandlingState state, |
| 134 | [[maybe_unused]] void *privateData) { |
| 135 | |
| 136 | // We only care about unhandled Promises |
| 137 | if (state != JS::PromiseRejectionHandlingState::Unhandled) { |
| 138 | return; |
| 139 | } |
| 140 | // If the `mutedErrors` option is set to True in `pm.eval`, eval errors or unhandled rejections should be ignored. |
| 141 | if (mutedErrors) { |
| 142 | return; |
| 143 | } |
| 144 | |
| 145 | // Test if there's no user-defined (or pmjs defined) exception handler on the Python event-loop |
| 146 | PyEventLoop loop = PyEventLoop::getRunningLoop(); |
| 147 | if (!loop.initialized()) return; |
| 148 | PyObject *customHandler = PyObject_GetAttrString(loop._loop, "_exception_handler"); // see https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/base_events.py#L1782 |
| 149 | if (customHandler == Py_None) { // we only have the default exception handler |
| 150 | // Set an exception handler to the event-loop |
| 151 | PyObject *pmModule = PyImport_ImportModule("pythonmonkey"); |
| 152 | PyObject *exceptionHandler = PyObject_GetAttrString(pmModule, "simpleUncaughtExceptionHandler"); |
| 153 | PyObject_CallMethod(loop._loop, "set_exception_handler", "O", exceptionHandler); |
| 154 | Py_DECREF(pmModule); |
| 155 | Py_DECREF(exceptionHandler); |
| 156 | } |
| 157 | Py_DECREF(customHandler); |
| 158 | |
| 159 | // Go ahead and send this unhandled Promise rejection to the exception handler on the Python event-loop |
| 160 | PyObject *pyFuture = PromiseType::getPyObject(cx, promise); // ref count == 2 |
| 161 | // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) |
| 162 | // See https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/futures.py#L108 |
| 163 | // or https://github.com/python/cpython/blob/v3.9.16/Modules/_asynciomodule.c#L1457-L1467 (It will actually use the C module by default, see futures.py#L417-L423) |
| 164 | Py_DECREF(pyFuture); // decreasing the reference count from 2 to 1, leaving one for the `onResolved` callback in `PromiseType::getPyObject`, which will be called very soon and clean up the reference |
| 165 | } |
| 166 | |
| 167 | void JobQueue::queueFinalizationRegistryCallback(JSFunction *callback) { |
| 168 | mozilla::Unused << finalizationRegistryCallbacks->append(callback); |
nothing calls this directly
no test coverage detected