JVM_IR: do not optimize suspend$$forInline functions
`$$forInline` functions do not pass through the state machine generator, and optimizing `Ref`s before that changes how assignments inside lambdas passed to `suspendCoroutine`, etc. behave: without a `Ref`, the assignment is not reflected in the continuation object, so the variable has old value on resumption. These functions will be optimized later, after they are inlined somewhere and the state machine is generated. ^KT-52198 Fixed
This commit is contained in:
+2
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
|
||||
class OptimizationClassBuilder(private val delegate: ClassBuilder, private val generationState: GenerationState) :
|
||||
@@ -36,6 +37,7 @@ class OptimizationClassBuilder(private val delegate: ClassBuilder, private val g
|
||||
): MethodVisitor {
|
||||
return OptimizationMethodVisitor(
|
||||
super.newMethod(origin, access, name, desc, signature, exceptions),
|
||||
origin.originKind == JvmDeclarationOriginKind.INLINE_VERSION_OF_SUSPEND_FUN,
|
||||
generationState, access, name, desc, signature, exceptions
|
||||
)
|
||||
}
|
||||
|
||||
+2
-1
@@ -34,6 +34,7 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class OptimizationMethodVisitor(
|
||||
delegate: MethodVisitor,
|
||||
private val mandatoryTransformationsOnly: Boolean,
|
||||
private val generationState: GenerationState,
|
||||
access: Int,
|
||||
name: String,
|
||||
@@ -67,7 +68,7 @@ class OptimizationMethodVisitor(
|
||||
normalizationMethodTransformer.transform("fake", methodNode)
|
||||
UninitializedStoresProcessor(methodNode).run()
|
||||
|
||||
if (canBeOptimized(methodNode) && !generationState.disableOptimization) {
|
||||
if (!mandatoryTransformationsOnly && canBeOptimized(methodNode) && !generationState.disableOptimization) {
|
||||
optimizationTransformer.transform("fake", methodNode)
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -5054,6 +5054,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt26658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52198.kt")
|
||||
public void testKt52198() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt52198.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("maxStackWithCrossinline.kt")
|
||||
public void testMaxStackWithCrossinline() throws Exception {
|
||||
|
||||
+6
@@ -5054,6 +5054,12 @@ public class FirLightTreeBlackBoxInlineCodegenTestGenerated extends AbstractFirL
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt26658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52198.kt")
|
||||
public void testKt52198() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt52198.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("maxStackWithCrossinline.kt")
|
||||
public void testMaxStackWithCrossinline() throws Exception {
|
||||
|
||||
+2
-1
@@ -33,7 +33,8 @@ enum class JvmDeclarationOriginKind {
|
||||
AUGMENTED_BUILTIN_API,
|
||||
ERASED_INLINE_CLASS,
|
||||
UNBOX_METHOD_OF_INLINE_CLASS,
|
||||
JVM_OVERLOADS
|
||||
JVM_OVERLOADS,
|
||||
INLINE_VERSION_OF_SUSPEND_FUN,
|
||||
}
|
||||
|
||||
class JvmDeclarationOrigin(
|
||||
|
||||
+9
-5
@@ -57,7 +57,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import java.io.File
|
||||
import java.lang.RuntimeException
|
||||
|
||||
class ClassCodegen private constructor(
|
||||
val irClass: IrClass,
|
||||
@@ -509,10 +508,15 @@ class ClassCodegen private constructor(
|
||||
private val IrDeclaration.descriptorOrigin: JvmDeclarationOrigin
|
||||
get() {
|
||||
val psiElement = PsiSourceManager.findPsiElement(this)
|
||||
return if (origin == IrDeclarationOrigin.FILE_CLASS)
|
||||
JvmDeclarationOrigin(JvmDeclarationOriginKind.PACKAGE_PART, psiElement, toIrBasedDescriptor())
|
||||
else
|
||||
OtherOrigin(psiElement, toIrBasedDescriptor())
|
||||
return when {
|
||||
origin == IrDeclarationOrigin.FILE_CLASS ->
|
||||
JvmDeclarationOrigin(JvmDeclarationOriginKind.PACKAGE_PART, psiElement, toIrBasedDescriptor())
|
||||
(this is IrSimpleFunction && isSuspend && isEffectivelyInlineOnly()) ||
|
||||
origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE ||
|
||||
origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE ->
|
||||
JvmDeclarationOrigin(JvmDeclarationOriginKind.INLINE_VERSION_OF_SUSPEND_FUN, psiElement, toIrBasedDescriptor())
|
||||
else -> OtherOrigin(psiElement, toIrBasedDescriptor())
|
||||
}
|
||||
}
|
||||
|
||||
private fun storeSerializedIr(serializedIr: ByteArray) {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// WITH_COROUTINES
|
||||
// WITH_STDLIB
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_IR_AGAINST_OLD
|
||||
// FILE: lib.kt
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun foo(value: String): String {
|
||||
var x = "fail"
|
||||
suspendCoroutineUninterceptedOrReturn<Unit> {
|
||||
x = value
|
||||
it.resume(Unit)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
suspend inline fun fooInline(value: String): String {
|
||||
var x = "fail"
|
||||
suspendCoroutineUninterceptedOrReturn<Unit> {
|
||||
x = value
|
||||
it.resume(Unit)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
import helpers.*
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
suspend {
|
||||
result = foo("O") + fooInline("K")
|
||||
}.startCoroutine(EmptyContinuation)
|
||||
return result
|
||||
}
|
||||
+6
@@ -5018,6 +5018,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt26658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52198.kt")
|
||||
public void testKt52198() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt52198.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("maxStackWithCrossinline.kt")
|
||||
public void testMaxStackWithCrossinline() throws Exception {
|
||||
|
||||
+6
@@ -5018,6 +5018,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt26658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52198.kt")
|
||||
public void testKt52198() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt52198.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("maxStackWithCrossinline.kt")
|
||||
public void testMaxStackWithCrossinline() throws Exception {
|
||||
|
||||
+6
@@ -5054,6 +5054,12 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt26658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52198.kt")
|
||||
public void testKt52198() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt52198.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("maxStackWithCrossinline.kt")
|
||||
public void testMaxStackWithCrossinline() throws Exception {
|
||||
|
||||
+6
@@ -5054,6 +5054,12 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt26658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52198.kt")
|
||||
public void testKt52198() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt52198.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("maxStackWithCrossinline.kt")
|
||||
public void testMaxStackWithCrossinline() throws Exception {
|
||||
|
||||
+6
@@ -5054,6 +5054,12 @@ public class IrSerializeCompileKotlinAgainstInlineKotlinTestGenerated extends Ab
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt26658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52198.kt")
|
||||
public void testKt52198() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt52198.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("maxStackWithCrossinline.kt")
|
||||
public void testMaxStackWithCrossinline() throws Exception {
|
||||
|
||||
+6
@@ -5054,6 +5054,12 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt26658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52198.kt")
|
||||
public void testKt52198() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt52198.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("maxStackWithCrossinline.kt")
|
||||
public void testMaxStackWithCrossinline() throws Exception {
|
||||
|
||||
+6
@@ -5018,6 +5018,12 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt26658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52198.kt")
|
||||
public void testKt52198() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/suspend/kt52198.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("maxStackWithCrossinline.kt")
|
||||
public void testMaxStackWithCrossinline() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user