Skip to content

Enable R8 optimization of Dispatchers.Main loading #1232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ import kotlin.coroutines.*
* Note that Android may have dummy [Thread.contextClassLoader] which is used by one-argument [ServiceLoader.load] function,
* see (https://stackoverflow.com/questions/13407006/android-class-loader-may-fail-for-processes-that-host-multiple-applications).
* So here we explicitly use two-argument `load` with a class-loader of [CoroutineExceptionHandler] class.
*
* We are explicitly using the `ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
* form of the ServiceLoader call to enable R8 optimization when compiled on Android.
*/
private val handlers: List<CoroutineExceptionHandler> = CoroutineExceptionHandler::class.java.let { serviceClass ->
ServiceLoader.load(serviceClass, serviceClass.classLoader).toList()
}
private val handlers: List<CoroutineExceptionHandler> = ServiceLoader.load(
CoroutineExceptionHandler::class.java,
CoroutineExceptionHandler::class.java.classLoader
).iterator().asSequence().toList()


internal actual fun handleCoroutineExceptionImpl(context: CoroutineContext, exception: Throwable) {
// use additional extension handlers
Expand Down
10 changes: 0 additions & 10 deletions kotlinx-coroutines-core/jvm/src/internal/FastServiceLoader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ import java.util.*
import java.util.jar.*
import java.util.zip.*

/**
* Name of the boolean property that enables using of [FastServiceLoader].
*/
private const val FAST_SERVICE_LOADER_PROPERTY_NAME = "kotlinx.coroutines.fast.service.loader"

/**
* A simplified version of [ServiceLoader].
* FastServiceLoader locates and instantiates all service providers named in configuration
Expand All @@ -25,12 +20,7 @@ private const val FAST_SERVICE_LOADER_PROPERTY_NAME = "kotlinx.coroutines.fast.s
internal object FastServiceLoader {
private const val PREFIX: String = "META-INF/services/"

private val FAST_SERVICE_LOADER_ENABLED = systemProp(FAST_SERVICE_LOADER_PROPERTY_NAME, true)

internal fun <S> load(service: Class<S>, loader: ClassLoader): List<S> {
if (!FAST_SERVICE_LOADER_ENABLED) {
return ServiceLoader.load(service, loader).toList()
}
return try {
loadProviders(service, loader)
} catch (e: Throwable) {
Expand Down
22 changes: 20 additions & 2 deletions kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,33 @@ import kotlinx.coroutines.*
import java.util.*
import kotlin.coroutines.*

/**
* Name of the boolean property that enables using of [FastServiceLoader].
*/
private const val FAST_SERVICE_LOADER_PROPERTY_NAME = "kotlinx.coroutines.fast.service.loader"

// Lazy loader for the main dispatcher
internal object MainDispatcherLoader {

private val FAST_SERVICE_LOADER_ENABLED = systemProp(FAST_SERVICE_LOADER_PROPERTY_NAME, true)

@JvmField
val dispatcher: MainCoroutineDispatcher = loadMainDispatcher()

private fun loadMainDispatcher(): MainCoroutineDispatcher {
return try {
val factories = MainDispatcherFactory::class.java.let { clz ->
FastServiceLoader.load(clz, clz.classLoader)
val factories = if (FAST_SERVICE_LOADER_ENABLED) {
MainDispatcherFactory::class.java.let { clz ->
FastServiceLoader.load(clz, clz.classLoader)
}
} else {
//We are explicitly using the
//`ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
//form of the ServiceLoader call to enable R8 optimization when compiled on Android.
ServiceLoader.load(
MainDispatcherFactory::class.java,
MainDispatcherFactory::class.java.classLoader
).iterator().asSequence().toList()
}
factories.maxBy { it.loadPriority }?.tryCreateDispatcher(factories)
?: MissingMainCoroutineDispatcher(null)
Expand Down