Skip to content

Commit b9b7d82

Browse files
wojtek-kalicinskiqwwdfsad
authored andcommitted
Enable R8 optimization of Dispatchers.Main loading
The developer still has to disable the FastServiceLoader manually if they're using R8. R8 is then able to optimize away the ServiceLoader and reflection entirely, resulting in direct class instantiation and no extra I/O on calling thread. Fixes #1231
1 parent 46e41f2 commit b9b7d82

File tree

3 files changed

+28
-15
lines changed

3 files changed

+28
-15
lines changed

kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@ import kotlin.coroutines.*
1313
* Note that Android may have dummy [Thread.contextClassLoader] which is used by one-argument [ServiceLoader.load] function,
1414
* see (https://stackoverflow.com/questions/13407006/android-class-loader-may-fail-for-processes-that-host-multiple-applications).
1515
* So here we explicitly use two-argument `load` with a class-loader of [CoroutineExceptionHandler] class.
16+
*
17+
* We are explicitly using the `ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
18+
* form of the ServiceLoader call to enable R8 optimization when compiled on Android.
1619
*/
17-
private val handlers: List<CoroutineExceptionHandler> = CoroutineExceptionHandler::class.java.let { serviceClass ->
18-
ServiceLoader.load(serviceClass, serviceClass.classLoader).toList()
19-
}
20+
private val handlers: List<CoroutineExceptionHandler> = ServiceLoader.load(
21+
CoroutineExceptionHandler::class.java,
22+
CoroutineExceptionHandler::class.java.classLoader
23+
).iterator().asSequence().toList()
24+
2025

2126
internal actual fun handleCoroutineExceptionImpl(context: CoroutineContext, exception: Throwable) {
2227
// use additional extension handlers

kotlinx-coroutines-core/jvm/src/internal/FastServiceLoader.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ import java.util.*
66
import java.util.jar.*
77
import java.util.zip.*
88

9-
/**
10-
* Name of the boolean property that enables using of [FastServiceLoader].
11-
*/
12-
private const val FAST_SERVICE_LOADER_PROPERTY_NAME = "kotlinx.coroutines.fast.service.loader"
13-
149
/**
1510
* A simplified version of [ServiceLoader].
1611
* FastServiceLoader locates and instantiates all service providers named in configuration
@@ -25,12 +20,7 @@ private const val FAST_SERVICE_LOADER_PROPERTY_NAME = "kotlinx.coroutines.fast.s
2520
internal object FastServiceLoader {
2621
private const val PREFIX: String = "META-INF/services/"
2722

28-
private val FAST_SERVICE_LOADER_ENABLED = systemProp(FAST_SERVICE_LOADER_PROPERTY_NAME, true)
29-
3023
internal fun <S> load(service: Class<S>, loader: ClassLoader): List<S> {
31-
if (!FAST_SERVICE_LOADER_ENABLED) {
32-
return ServiceLoader.load(service, loader).toList()
33-
}
3424
return try {
3525
loadProviders(service, loader)
3626
} catch (e: Throwable) {

kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,33 @@ import kotlinx.coroutines.*
44
import java.util.*
55
import kotlin.coroutines.*
66

7+
/**
8+
* Name of the boolean property that enables using of [FastServiceLoader].
9+
*/
10+
private const val FAST_SERVICE_LOADER_PROPERTY_NAME = "kotlinx.coroutines.fast.service.loader"
11+
712
// Lazy loader for the main dispatcher
813
internal object MainDispatcherLoader {
14+
15+
private val FAST_SERVICE_LOADER_ENABLED = systemProp(FAST_SERVICE_LOADER_PROPERTY_NAME, true)
16+
917
@JvmField
1018
val dispatcher: MainCoroutineDispatcher = loadMainDispatcher()
1119

1220
private fun loadMainDispatcher(): MainCoroutineDispatcher {
1321
return try {
14-
val factories = MainDispatcherFactory::class.java.let { clz ->
15-
FastServiceLoader.load(clz, clz.classLoader)
22+
val factories = if (FAST_SERVICE_LOADER_ENABLED) {
23+
MainDispatcherFactory::class.java.let { clz ->
24+
FastServiceLoader.load(clz, clz.classLoader)
25+
}
26+
} else {
27+
//We are explicitly using the
28+
//`ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
29+
//form of the ServiceLoader call to enable R8 optimization when compiled on Android.
30+
ServiceLoader.load(
31+
MainDispatcherFactory::class.java,
32+
MainDispatcherFactory::class.java.classLoader
33+
).iterator().asSequence().toList()
1634
}
1735
factories.maxBy { it.loadPriority }?.tryCreateDispatcher(factories)
1836
?: MissingMainCoroutineDispatcher(null)

0 commit comments

Comments
 (0)