The implementation for the JVM looks like this:
internal actual fun handleCoroutineExceptionImpl(
context: CoroutineContext,
exception: Throwable) {
ServiceLoader.load(CoroutineExceptionHandler::class.java)
.forEach { handler ->
handler.handleException(context, exception)
}
val currentThread = Thread.currentThread()
currentThread.uncaughtExceptionHandler
.uncaughtException(currentThread, exception)
}
It looks for exception handlers using the ServiceLoader and forwards the exception to all the ones it can find. It also forwards the exception to the handler of the current thread.