Skip to content

Commit

Permalink
Make call to service loader in reactor integrations optimizable by R8 (
Browse files Browse the repository at this point in the history
  • Loading branch information
qwwdfsad committed Mar 6, 2020
1 parent 3592a8c commit 1eae238
Show file tree
Hide file tree
Showing 4 changed files with 10 additions and 19 deletions.
10 changes: 0 additions & 10 deletions reactive/kotlinx-coroutines-reactive/src/Await.kt
Expand Up @@ -82,16 +82,6 @@ public suspend fun <T> Publisher<T>.awaitSingle(): T = awaitOne(Mode.SINGLE)

// ------------------------ private ------------------------

// ContextInjector service is implemented in `kotlinx-coroutines-reactor` module only.
// If `kotlinx-coroutines-reactor` module is not included, the list is empty.
private val contextInjectors: Array<ContextInjector> =
ServiceLoader.load(ContextInjector::class.java, ContextInjector::class.java.classLoader).iterator().asSequence().toList().toTypedArray() // R8 opto

private fun <T> Publisher<T>.injectCoroutineContext(coroutineContext: CoroutineContext) =
contextInjectors.fold(this) { pub, contextInjector ->
contextInjector.injectCoroutineContext(pub, coroutineContext)
}

private enum class Mode(val s: String) {
FIRST("awaitFirst"),
FIRST_OR_DEFAULT("awaitFirstOrDefault"),
Expand Down
9 changes: 5 additions & 4 deletions reactive/kotlinx-coroutines-reactive/src/ReactiveFlow.kt
Expand Up @@ -140,13 +140,14 @@ private class ReactiveSubscriber<T : Any>(

// ContextInjector service is implemented in `kotlinx-coroutines-reactor` module only.
// If `kotlinx-coroutines-reactor` module is not included, the list is empty.
private val contextInjectors: List<ContextInjector> =
ServiceLoader.load(ContextInjector::class.java, ContextInjector::class.java.classLoader).toList()
private val contextInjectors: Array<ContextInjector> =
ServiceLoader.load(ContextInjector::class.java, ContextInjector::class.java.classLoader)
.iterator().asSequence()
.toList().toTypedArray() // R8 opto

private fun <T> Publisher<T>.injectCoroutineContext(coroutineContext: CoroutineContext) =
internal fun <T> Publisher<T>.injectCoroutineContext(coroutineContext: CoroutineContext) =
contextInjectors.fold(this) { pub, contextInjector -> contextInjector.injectCoroutineContext(pub, coroutineContext) }


/**
* Adapter that transforms [Flow] into TCK-complaint [Publisher].
* [cancel] invocation cancels the original flow.
Expand Down
4 changes: 2 additions & 2 deletions ui/kotlinx-coroutines-android/build.gradle
Expand Up @@ -77,7 +77,7 @@ task runR8(type: RunR8Task, dependsOn: 'jar'){
inputConfig = file('testdata/r8-test-rules.pro')
}

task runR8NoOptim(type: RunR8Task, dependsOn: 'jar'){
task runR8NoOptim(type: RunR8Task, dependsOn: 'jar') {
outputDex = unOptimizedDexDir
inputConfig = file('testdata/r8-test-rules-no-optim.pro')
}
Expand All @@ -103,4 +103,4 @@ tasks.withType(dokka.getClass()) {
url = new URL("https://developer.android.com/reference/")
packageListUrl = projectDir.toPath().resolve("package.list").toUri().toURL()
}
}
}
Expand Up @@ -16,7 +16,7 @@ class R8ServiceLoaderOptimizationTest : TestBase() {
private val r8DexNoOptim = File(System.getProperty("noOptimDexPath")!!).asDexFile()

@Test
fun noServiceLoaderCalls() {
fun testNoServiceLoaderCalls() {
val serviceLoaderInvocations = r8Dex.types.any {
it.type == "Ljava/util/ServiceLoader;"
}
Expand All @@ -28,7 +28,7 @@ class R8ServiceLoaderOptimizationTest : TestBase() {
}

@Test
fun androidDispatcherIsKept() {
fun testAndroidDispatcherIsKept() {
val hasAndroidDispatcher = r8DexNoOptim.classes.any {
it.type == "Lkotlinx/coroutines/android/AndroidDispatcherFactory;"
}
Expand All @@ -38,7 +38,7 @@ class R8ServiceLoaderOptimizationTest : TestBase() {

@Test
@Ignore
fun noOptimRulesMatch() {
fun testNoOptimRulesMatch() {
val paths = listOf(
"META-INF/com.android.tools/proguard/coroutines.pro",
"META-INF/proguard/coroutines.pro",
Expand Down

0 comments on commit 1eae238

Please sign in to comment.