diff --git a/compiler/testData/codegen/bytecodeText/coroutines/cleanup/backEdge.kt b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/backEdge.kt new file mode 100644 index 00000000000..9c045b5e977 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/backEdge.kt @@ -0,0 +1,16 @@ +fun blackhole(vararg a: Any?) {} + +suspend fun dummy() {} + +suspend fun test() { + for (i in 0..10) { + // Should be cleanup, since there is a back edge from the rest of the loop + dummy() + val a = "" + dummy() + blackhole(a) + } +} + +// 1 ACONST_NULL +// 2 PUTFIELD .*L\$0 : Ljava/lang/Object; \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/cleanup/if.kt b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/if.kt new file mode 100644 index 00000000000..131b8ffe505 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/if.kt @@ -0,0 +1,24 @@ +fun blackhole(vararg a: Any?) {} + +suspend fun dummy() {} + +fun check(): Boolean = true + +suspend fun test() { + if (check()) { + val a = "" + dummy() + blackhole(a) + } else { + val a = "" + val b = "" + dummy() + blackhole(a, b) + } + // Cleanup both a and b, since the compiler does not know, which branch is going to executed + dummy() +} + +// 2 ACONST_NULL +// 3 PUTFIELD .*L\$0 : Ljava/lang/Object; +// 2 PUTFIELD .*L\$1 : Ljava/lang/Object; \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullCleanup.kt b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullCleanup.kt new file mode 100644 index 00000000000..33090f7aed9 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullCleanup.kt @@ -0,0 +1,17 @@ +fun blackhole(vararg a: Any?) {} + +suspend fun dummy() {} + +suspend fun test() { + var a: String? = "" + dummy() + blackhole(a) + a = null + // a is null, known at compile time, do not spill, but cleanup + dummy() + blackhole(a) +} + +// jsut before suspension point +// 1 ACONST_NULL +// 2 PUTFIELD .*L\$0 : Ljava/lang/Object; \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullNotSpill.kt b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullNotSpill.kt new file mode 100644 index 00000000000..ccf01963f63 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullNotSpill.kt @@ -0,0 +1,15 @@ +fun blackhole(vararg a: Any?) {} + +suspend fun dummy() {} + +suspend fun test() { + val a = null + // a is null, known at compile time, do not spill + dummy() + blackhole(a) + dummy() +} + +// before and after suspension point +// 2 ACONST_NULL +// 0 PUTFIELD .*L\$0 : Ljava/lang/Object; \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/cleanup/simple.kt b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/simple.kt new file mode 100644 index 00000000000..d497ddadffa --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/simple.kt @@ -0,0 +1,14 @@ +fun blackhole(vararg a: Any?) {} + +suspend fun dummy() {} + +suspend fun test() { + val a = "" + dummy() + blackhole(a) + // a is dead, cleanup + dummy() +} + +// 1 ACONST_NULL +// 2 PUTFIELD .*L\$0 : Ljava/lang/Object; \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/cleanup/when.kt b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/when.kt new file mode 100644 index 00000000000..be51a324aaf --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/when.kt @@ -0,0 +1,34 @@ +fun blackhole(vararg a: Any?) {} + +suspend fun dummy() {} + +fun check(): Int = 1 + +suspend fun test() { + when (check()) { + 0 -> { + val a = "" + dummy() + blackhole(a) + } + 1 -> { + val a = "" + val b = "" + dummy() + blackhole(a, b) + } + else -> { + val a = "" + val b = "" + val c = 1 + dummy() + blackhole(a, b, c) + } + } + // Cleanup both a and b, but c is primitive, so no need to clean it up + dummy() +} + +// 2 ACONST_NULL +// 4 PUTFIELD .*L\$0 : Ljava/lang/Object; +// 3 PUTFIELD .*L\$1 : Ljava/lang/Object; \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 8a4c1d6bd0c..17bf34e891d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1451,6 +1451,49 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/coroutines/varValueConflictsWithTableSameSort.kt"); } + @TestMetadata("compiler/testData/codegen/bytecodeText/coroutines/cleanup") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Cleanup extends AbstractBytecodeTextTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInCleanup() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/coroutines/cleanup"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("backEdge.kt") + public void testBackEdge() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/backEdge.kt"); + } + + @TestMetadata("if.kt") + public void testIf() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/if.kt"); + } + + @TestMetadata("nullCleanup.kt") + public void testNullCleanup() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullCleanup.kt"); + } + + @TestMetadata("nullNotSpill.kt") + public void testNullNotSpill() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullNotSpill.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/simple.kt"); + } + + @TestMetadata("when.kt") + public void testWhen() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/when.kt"); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/coroutines/debug") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index ec7bc168de8..0e40e836213 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -1456,6 +1456,49 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/coroutines/varValueConflictsWithTableSameSort.kt"); } + @TestMetadata("compiler/testData/codegen/bytecodeText/coroutines/cleanup") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Cleanup extends AbstractIrBytecodeTextTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInCleanup() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/coroutines/cleanup"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("backEdge.kt") + public void testBackEdge() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/backEdge.kt"); + } + + @TestMetadata("if.kt") + public void testIf() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/if.kt"); + } + + @TestMetadata("nullCleanup.kt") + public void testNullCleanup() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullCleanup.kt"); + } + + @TestMetadata("nullNotSpill.kt") + public void testNullNotSpill() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullNotSpill.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/simple.kt"); + } + + @TestMetadata("when.kt") + public void testWhen() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/cleanup/when.kt"); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/coroutines/debug") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)