From 37b364a70aa6c4f759662876573aa646bfb4051d Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 17 Jan 2017 16:04:32 +0300 Subject: [PATCH] Fix processing of uninitialized instances for coroutines The problem is that code in the attached test led to VerifyError at runtime because the Bar's uninitialized instance created in 'map' was being stored to the field (leaked from the JVM point of view). The actual problem was that after repeating visiting of NEW operation we used to drop the set of already visited copy usages. For clarification see the comment before 'processUninitializedStores' #KT-15016 Fixed --- .../coroutines/processUninitializedStores.kt | 2 +- .../codegen/box/coroutines/kt15016.kt | 47 ++++++++++++++++ .../light-analysis/coroutines/kt15016.txt | 55 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 ++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++ ...LightAnalysisModeCodegenTestGenerated.java | 6 ++ .../semantics/JsCodegenBoxTestGenerated.java | 6 ++ 7 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/box/coroutines/kt15016.kt create mode 100644 compiler/testData/codegen/light-analysis/coroutines/kt15016.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/processUninitializedStores.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/processUninitializedStores.kt index b03d99c440e..5e5983dc629 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/processUninitializedStores.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/processUninitializedStores.kt @@ -160,7 +160,7 @@ private class UninitializedNewValueMarkerInterpreter : OptimizationBasicInterpre val uninitializedValuesToCopyUsages = hashMapOf>() override fun newOperation(insn: AbstractInsnNode): BasicValue? { if (insn.opcode == Opcodes.NEW) { - uninitializedValuesToCopyUsages[insn] = mutableSetOf() + uninitializedValuesToCopyUsages.getOrPut(insn) { mutableSetOf() } return UninitializedNewValue(insn as TypeInsnNode, insn.desc) } return super.newOperation(insn) diff --git a/compiler/testData/codegen/box/coroutines/kt15016.kt b/compiler/testData/codegen/box/coroutines/kt15016.kt new file mode 100644 index 00000000000..99552c1c01c --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/kt15016.kt @@ -0,0 +1,47 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import kotlin.coroutines.intrinsics.SUSPENDED_MARKER +import kotlin.coroutines.intrinsics.suspendCoroutineOrReturn +import kotlin.coroutines.startCoroutine + +class Bar(val x: Any) +inline fun Any.map(transform: (Any) -> Any) { + when (this) { + is Foo -> Bar(transform(value)) + } +} + +class Foo(val value: Any) { + companion object { + inline fun of(f: () -> Unit): Any = try { + Foo(f()) + } catch(ex: Exception) { + Foo(Unit) + } + } +} + +suspend fun suspendHere(): String = suspendCoroutineOrReturn { x -> + x.resume("OK") + SUSPENDED_MARKER +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var result = "" + + builder { + Foo.of { + + }.map { + result = suspendHere() + Unit + } + } + + return result +} diff --git a/compiler/testData/codegen/light-analysis/coroutines/kt15016.txt b/compiler/testData/codegen/light-analysis/coroutines/kt15016.txt new file mode 100644 index 00000000000..e522c80b011 --- /dev/null +++ b/compiler/testData/codegen/light-analysis/coroutines/kt15016.txt @@ -0,0 +1,55 @@ +@kotlin.Metadata +public final class Bar { + private final @org.jetbrains.annotations.NotNull field x: java.lang.Object + public method (@org.jetbrains.annotations.NotNull p0: java.lang.Object): void + public final @org.jetbrains.annotations.NotNull method getX(): java.lang.Object +} + +@kotlin.Metadata +public final class CoroutineUtilKt { + public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation + public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation +} + +@kotlin.Metadata +public class EmptyContinuation { + public final static field Companion: EmptyContinuation.Companion + private final @org.jetbrains.annotations.NotNull field context: kotlin.coroutines.CoroutineContext + inner class EmptyContinuation/Companion + public @synthetic.kotlin.jvm.GeneratedByJvmOverloads method (): void + public method (@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.CoroutineContext): void + public synthetic method (p0: kotlin.coroutines.CoroutineContext, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void + public @org.jetbrains.annotations.NotNull method getContext(): kotlin.coroutines.CoroutineContext + public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void + public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void +} + +@kotlin.Metadata +public final static class EmptyContinuation/Companion { + inner class EmptyContinuation/Companion + private method (): void +} + +@kotlin.Metadata +public final class Foo { + public final static field Companion: Foo.Companion + private final @org.jetbrains.annotations.NotNull field value: java.lang.Object + inner class Foo/Companion + public method (@org.jetbrains.annotations.NotNull p0: java.lang.Object): void + public final @org.jetbrains.annotations.NotNull method getValue(): java.lang.Object +} + +@kotlin.Metadata +public final static class Foo/Companion { + inner class Foo/Companion + private method (): void + public final @org.jetbrains.annotations.NotNull method of(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Object +} + +@kotlin.Metadata +public final class Kt15016Kt { + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String + public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void + public final static method map(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function1): void + public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 5e8a374341c..68b12869cd7 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -4703,6 +4703,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("kt15016.kt") + public void testKt15016() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/kt15016.kt"); + doTest(fileName); + } + @TestMetadata("lastExpressionIsLoop.kt") public void testLastExpressionIsLoop() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 2c174024627..28745b4890f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4703,6 +4703,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt15016.kt") + public void testKt15016() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/kt15016.kt"); + doTest(fileName); + } + @TestMetadata("lastExpressionIsLoop.kt") public void testLastExpressionIsLoop() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java index a5d495ea6de..63a1dd37306 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java @@ -4703,6 +4703,12 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis doTest(fileName); } + @TestMetadata("kt15016.kt") + public void testKt15016() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/kt15016.kt"); + doTest(fileName); + } + @TestMetadata("lastExpressionIsLoop.kt") public void testLastExpressionIsLoop() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index ce4db34b56f..cdcdf5d1614 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -5442,6 +5442,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("kt15016.kt") + public void testKt15016() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/kt15016.kt"); + doTest(fileName); + } + @TestMetadata("lastExpressionIsLoop.kt") public void testLastExpressionIsLoop() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt");