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:
pyos
2022-04-29 13:29:42 +02:00
committed by Ilmir Usmanov
parent 153f878df4
commit effd21d074
14 changed files with 109 additions and 7 deletions
@@ -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
)
}
@@ -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)
}
@@ -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 {
@@ -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 {
@@ -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(
@@ -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) {
+40
View File
@@ -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
}
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {