Skip to content

Commit 59dc652

Browse files
committed
kotlinx-coroutines-debug: Fix split-package with the -core module
- `kotlinx.coroutines.debug.internal` owned by coroutines-core - `kotlinx.coroutines.debug` owned by coroutines-debug (Which also reflects the nature of the debug module, which exposes _some_ public API from the .debug.internal package) This requires moving: - AgentPremain -> .debug.internal - ByteBuddyDynamicAttach -> .debug - NoOpProbes.kt -> .debug
1 parent 6c6df2b commit 59dc652

File tree

16 files changed

+121
-17
lines changed

16 files changed

+121
-17
lines changed

Diff for: integration-testing/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.kotlin
2+
kotlin-js-store

Diff for: integration-testing/build.gradle

+48-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ repositories {
5252
java {
5353
sourceCompatibility = JavaVersion.VERSION_1_8
5454
targetCompatibility = JavaVersion.VERSION_1_8
55+
modularity.inferModulePath = true
5556
}
5657

5758
dependencies {
@@ -117,6 +118,46 @@ sourceSets {
117118
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
118119
}
119120
}
121+
122+
debugDynamicAgentJpmsTest {
123+
compileClasspath += sourceSets.test.runtimeClasspath
124+
runtimeClasspath += sourceSets.test.runtimeClasspath
125+
126+
dependencies {
127+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
128+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-debug:$coroutines_version"
129+
}
130+
}
131+
132+
tasks.compileDebugDynamicAgentJpmsTestKotlin.configure {
133+
compilerOptions {
134+
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
135+
}
136+
}
137+
138+
tasks.compileDebugDynamicAgentJpmsTestJava.configure {
139+
options.release.set(17)
140+
}
141+
142+
debugDynamicAgentJpmsTest {
143+
compileClasspath += sourceSets.test.runtimeClasspath
144+
runtimeClasspath += sourceSets.test.runtimeClasspath
145+
146+
dependencies {
147+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
148+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-debug:$coroutines_version"
149+
}
150+
}
151+
152+
tasks.compileDebugDynamicAgentJpmsTestKotlin.configure {
153+
compilerOptions {
154+
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
155+
}
156+
}
157+
158+
tasks.compileDebugDynamicAgentJpmsTestJava.configure {
159+
options.release.set(17)
160+
}
120161
}
121162

122163
compileDebugAgentTestKotlin {
@@ -154,6 +195,12 @@ task debugDynamicAgentTest(type: Test) {
154195
classpath = sourceSet.runtimeClasspath
155196
}
156197

198+
task debugDynamicAgentJpmsTest(type: Test) {
199+
def sourceSet = sourceSets.debugDynamicAgentJpmsTest
200+
testClassesDirs = sourceSet.output.classesDirs
201+
classpath = sourceSet.runtimeClasspath
202+
}
203+
157204
task coreAgentTest(type: Test) {
158205
def sourceSet = sourceSets.coreAgentTest
159206
def coroutinesCoreJar = sourceSet.runtimeClasspath.filter {it.name == "kotlinx-coroutines-core-jvm-${coroutines_version}.jar" }.singleFile
@@ -167,7 +214,7 @@ compileTestKotlin {
167214
}
168215

169216
check {
170-
dependsOn([jvmCoreTest, debugDynamicAgentTest, mavenTest, debugAgentTest, coreAgentTest, 'smokeTest:build'])
217+
dependsOn([jvmCoreTest, debugDynamicAgentTest, mavenTest, debugAgentTest, coreAgentTest, debugDynamicAgentJpmsTest, 'smokeTest:build'])
171218
}
172219
compileKotlin {
173220
kotlinOptions {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module debug.dynamic.agent.jpms.test {
2+
requires kotlin.stdlib;
3+
requires kotlinx.coroutines.core;
4+
requires kotlinx.coroutines.debug;
5+
requires junit;
6+
requires kotlin.test;
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
@file:OptIn(ExperimentalCoroutinesApi::class)
2+
3+
import org.junit.*
4+
import kotlinx.coroutines.*
5+
import kotlinx.coroutines.debug.*
6+
import org.junit.Ignore
7+
import org.junit.Test
8+
import java.io.*
9+
import java.lang.IllegalStateException
10+
import kotlin.test.*
11+
12+
class DynamicAttachDebugTest {
13+
14+
/**
15+
* Using:
16+
*
17+
* jvmArgs("--add-exports=kotlinx.coroutines.debug/kotlinx.coroutines.repackaged.net.bytebuddy=com.sun.jna")
18+
* jvmArgs("--add-exports=kotlinx.coroutines.debug/kotlinx.coroutines.repackaged.net.bytebuddy.agent=com.sun.jna")
19+
*
20+
*
21+
* Caused by: java.lang.IllegalStateException: The Byte Buddy agent is not loaded or this method is not called via the system class loader
22+
* at kotlinx.coroutines.debug/kotlinx.coroutines.repackaged.net.bytebuddy.agent.Installer.getInstrumentation(Installer.java:61)
23+
* ... 54 more
24+
*/
25+
@Ignore("shaded byte-buddy does not work with JPMS")
26+
@Test
27+
fun testAgentDumpsCoroutines() =
28+
DebugProbes.withDebugProbes {
29+
runBlocking {
30+
val baos = ByteArrayOutputStream()
31+
DebugProbes.dumpCoroutines(PrintStream(baos))
32+
// if the agent works, then dumps should contain something,
33+
// at least the fact that this test is running.
34+
Assert.assertTrue(baos.toString().contains("testAgentDumpsCoroutines"))
35+
}
36+
}
37+
38+
@Test()
39+
fun testAgentIsNotInstalled() {
40+
assertEquals(false, DebugProbes.isInstalled)
41+
assertFailsWith<IllegalStateException> {
42+
DebugProbes.dumpCoroutines(PrintStream(ByteArrayOutputStream()))
43+
}
44+
}
45+
46+
}

Diff for: kotlinx-coroutines-core/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ val allMetadataJar by tasks.getting(Jar::class) { setupManifest(this) }
188188
fun setupManifest(jar: Jar) {
189189
jar.manifest {
190190
attributes(mapOf(
191-
"Premain-Class" to "kotlinx.coroutines.debug.AgentPremain",
191+
"Premain-Class" to "kotlinx.coroutines.debug.internal.AgentPremain",
192192
"Can-Retransform-Classes" to "true",
193193
))
194194
}

Diff for: kotlinx-coroutines-core/jvm/resources/META-INF/com.android.tools/proguard/coroutines.pro

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
volatile <fields>;
1717
}
1818

19-
# These classes are only required by kotlinx.coroutines.debug.AgentPremain, which is only loaded when
19+
# These classes are only required by kotlinx.coroutines.debug.internal.AgentPremain, which is only loaded when
2020
# kotlinx-coroutines-core is used as a Java agent, so these are not needed in contexts where ProGuard is used.
2121
-dontwarn java.lang.instrument.ClassFileTransformer
2222
-dontwarn sun.misc.SignalHandler

Diff for: kotlinx-coroutines-core/jvm/resources/META-INF/com.android.tools/r8/coroutines.pro

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
volatile <fields>;
1313
}
1414

15-
# These classes are only required by kotlinx.coroutines.debug.AgentPremain, which is only loaded when
15+
# These classes are only required by kotlinx.coroutines.debug.internal.AgentPremain, which is only loaded when
1616
# kotlinx-coroutines-core is used as a Java agent, so these are not needed in contexts where ProGuard is used.
1717
-dontwarn java.lang.instrument.ClassFileTransformer
1818
-dontwarn sun.misc.SignalHandler

Diff for: kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
volatile <fields>;
1717
}
1818

19-
# These classes are only required by kotlinx.coroutines.debug.AgentPremain, which is only loaded when
19+
# These classes are only required by kotlinx.coroutines.debug.internal.AgentPremain, which is only loaded when
2020
# kotlinx-coroutines-core is used as a Java agent, so these are not needed in contexts where ProGuard is used.
2121
-dontwarn java.lang.instrument.ClassFileTransformer
2222
-dontwarn sun.misc.SignalHandler

Diff for: kotlinx-coroutines-core/jvm/src/debug/internal/AgentInstallationType.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ package kotlinx.coroutines.debug.internal
33
/**
44
* Object used to differentiate between agent installed statically or dynamically.
55
* This is done in a separate object so [DebugProbesImpl] can check for static installation
6-
* without having to depend on [kotlinx.coroutines.debug.AgentPremain], which is not compatible with Android.
6+
* without having to depend on [AgentPremain], which is not compatible with Android.
77
* Otherwise, access to `AgentPremain.isInstalledStatically` triggers the load of its internal `ClassFileTransformer`
88
* that is not available on Android.
9+
*
10+
* Usage Note: Fleet (Reflection): FleetDebugProbes
11+
* Usage Note: Android (Hard Coded, ignored for Leak Detection)
12+
* Usage Note: IntelliJ (Suppress KotlinInternalInJava): CoroutineDumpState
913
*/
1014
internal object AgentInstallationType {
1115
internal var isInstalledStatically = false

Diff for: kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt renamed to kotlinx-coroutines-core/jvm/src/debug/internal/AgentPremain.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
package kotlinx.coroutines.debug
1+
package kotlinx.coroutines.debug.internal
22

33
import android.annotation.*
4-
import kotlinx.coroutines.debug.internal.*
54
import org.codehaus.mojo.animal_sniffer.*
65
import sun.misc.*
76
import java.lang.instrument.*

Diff for: kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ internal object DebugProbesImpl {
5151

5252
@Suppress("UNCHECKED_CAST")
5353
private fun getDynamicAttach(): Function1<Boolean, Unit>? = runCatching {
54-
val clz = Class.forName("kotlinx.coroutines.debug.internal.ByteBuddyDynamicAttach")
54+
val clz = Class.forName("kotlinx.coroutines.debug.ByteBuddyDynamicAttach")
5555
val ctor = clz.constructors[0]
5656
ctor.newInstance() as Function1<Boolean, Unit>
5757
}.getOrNull()

Diff for: kotlinx-coroutines-core/jvm/src/module-info.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
requires transitive kotlin.stdlib;
66
requires kotlinx.atomicfu;
77

8-
// these are used by kotlinx.coroutines.debug.AgentPremain
8+
// these are used by kotlinx.coroutines.debug.internal.AgentPremain
99
requires static java.instrument; // contains java.lang.instrument.*
1010
requires static jdk.unsupported; // contains sun.misc.Signal
1111

1212
exports kotlinx.coroutines;
1313
exports kotlinx.coroutines.channels;
14-
exports kotlinx.coroutines.debug;
1514
exports kotlinx.coroutines.debug.internal;
1615
exports kotlinx.coroutines.flow;
1716
exports kotlinx.coroutines.flow.internal;

Diff for: kotlinx-coroutines-debug/build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ val shadowJar by tasks.existing(ShadowJar::class) {
6868
manifest {
6969
attributes(
7070
mapOf(
71-
"Premain-Class" to "kotlinx.coroutines.debug.AgentPremain",
71+
"Premain-Class" to "kotlinx.coroutines.debug.internal.AgentPremain",
7272
"Can-Redefine-Classes" to "true",
7373
"Multi-Release" to "true"
7474
)
@@ -104,7 +104,7 @@ kover {
104104
filters {
105105
excludes {
106106
// Never used, safety mechanism
107-
classes("kotlinx.coroutines.debug.internal.NoOpProbesKt")
107+
classes("kotlinx.coroutines.debug.NoOpProbesKt")
108108
}
109109
}
110110
}

Diff for: kotlinx-coroutines-debug/src/internal/Attach.kt renamed to kotlinx-coroutines-debug/src/Attach.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@file:Suppress("unused")
2-
package kotlinx.coroutines.debug.internal
2+
package kotlinx.coroutines.debug
33

44
import net.bytebuddy.*
55
import net.bytebuddy.agent.*
@@ -28,7 +28,7 @@ internal class ByteBuddyDynamicAttach : Function1<Boolean, Unit> {
2828

2929
private fun detach() {
3030
val cl = Class.forName("kotlin.coroutines.jvm.internal.DebugProbesKt")
31-
val cl2 = Class.forName("kotlinx.coroutines.debug.internal.NoOpProbesKt")
31+
val cl2 = Class.forName("kotlinx.coroutines.debug.NoOpProbesKt")
3232
ByteBuddy()
3333
.redefine(cl2)
3434
.name(cl.name)

Diff for: kotlinx-coroutines-debug/src/internal/NoOpProbes.kt renamed to kotlinx-coroutines-debug/src/NoOpProbes.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@file:Suppress("unused", "UNUSED_PARAMETER")
22

3-
package kotlinx.coroutines.debug.internal
3+
package kotlinx.coroutines.debug
44

55
import kotlin.coroutines.*
66

Diff for: kotlinx-coroutines-debug/src/module-info.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
requires org.junit.jupiter.api;
99
requires org.junit.platform.commons;
1010

11-
// exports kotlinx.coroutines.debug; // already exported by kotlinx.coroutines.core
11+
exports kotlinx.coroutines.debug;
1212
exports kotlinx.coroutines.debug.junit4;
1313
exports kotlinx.coroutines.debug.junit5;
1414
}

0 commit comments

Comments
 (0)