From e8c52e0a8f9b948d2ecc9ae17fffb0a87b75eebf Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Wed, 16 Jan 2019 21:10:57 +0300 Subject: [PATCH] Do not mark fake inliner variables as alive This prevents them from spilling. #KT-29317 Fixed --- .../CoroutineTransformerMethodVisitor.kt | 11 ++------ .../optimization/common/variableLiveness.kt | 9 ++++--- .../inline/inlineSuspendReifiedNoSpilling.kt | 25 +++++++++++++++++++ .../codegen/BytecodeTextTestGenerated.java | 5 ++++ .../codegen/IrBytecodeTextTestGenerated.java | 5 ++++ 5 files changed, 43 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeText/inline/inlineSuspendReifiedNoSpilling.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index a14743f62bb..4323fd68c01 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -498,12 +498,6 @@ class CoroutineTransformerMethodVisitor( val frames = performRefinedTypeAnalysis(methodNode, containingClassInternalName) fun AbstractInsnNode.index() = instructions.indexOf(this) - fun Int.isInlinerFakeVariable(index: Int) = methodNode.localVariables.any { - (it.name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT) || it.name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION)) - && it.index == this - && it.start.index() <= index && index <= it.end.index() - } - // We postpone these actions because they change instruction indices that we use when obtaining frames val postponedActions = mutableListOf<() -> Unit>() val maxVarsCountByType = mutableMapOf() @@ -545,9 +539,8 @@ class CoroutineTransformerMethodVisitor( // k + 2 - exception val variablesToSpill = (0 until localsCount) - .filterNot { - it in setOf(continuationIndex, dataIndex, exceptionIndex) || it.isInlinerFakeVariable(suspensionCallBegin.index()) - }.map { Pair(it, frame.getLocal(it)) } + .filterNot { it in setOf(continuationIndex, dataIndex, exceptionIndex) } + .map { Pair(it, frame.getLocal(it)) } .filter { (index, value) -> (index == 0 && needDispatchReceiver && isForNamedFunction) || (value != StrictBasicValue.UNINITIALIZED_VALUE && livenessFrame.isAlive(index)) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt index f34acb90f4d..133ffa784b8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.codegen.optimization.common import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer +import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode import org.jetbrains.org.objectweb.asm.tree.IincInsnNode @@ -78,11 +79,13 @@ private fun useVar( ) { val index = node.instructions.indexOf(insn) node.localVariables.filter { - node.instructions.indexOf(it.start) < index && index < node.instructions.indexOf(it.end) && + // Inliner fake variables, despite being present in LVT, are not read, thus are always dead + !it.name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT) && !it.name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) && + node.instructions.indexOf(it.start) < index && index < node.instructions.indexOf(it.end) && Type.getType(it.desc).sort == typeAnnotatedFrame?.getLocal(it.index)?.type?.sort }.forEach { - frame.markAlive(it.index) - } + frame.markAlive(it.index) + } if (insn is VarInsnNode && insn.isLoadOperation()) { frame.markAlive(insn.`var`) diff --git a/compiler/testData/codegen/bytecodeText/inline/inlineSuspendReifiedNoSpilling.kt b/compiler/testData/codegen/bytecodeText/inline/inlineSuspendReifiedNoSpilling.kt new file mode 100644 index 00000000000..0bde89ef84d --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inline/inlineSuspendReifiedNoSpilling.kt @@ -0,0 +1,25 @@ +// IGNORE_BACKEND: JVM_IR + +interface ApplicationCall + +interface AuthenticationService { + suspend fun execute(request: Any): Any +} + +suspend fun dummy() = Any() + +suspend inline fun ApplicationCall.receiveJSON(): Type { + return dummy() as Type +} + +suspend inline fun ApplicationCall.respond(message: Any) { +} + +suspend fun ApplicationCall.test(authenticationService: AuthenticationService) { + respond(authenticationService.execute(receiveJSON())) +} + +// 2 ISTORE 5 +// 0 ILOAD 5 +// 1 \$i\$f\$receiveJSON I .* 5 +// 1 \$i\$f\$respond I .* 5 diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 874c4355f7e..69134bad9dc 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1978,6 +1978,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/inline/inlineReturnsNothing3.kt"); } + @TestMetadata("inlineSuspendReifiedNoSpilling.kt") + public void testInlineSuspendReifiedNoSpilling() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/inline/inlineSuspendReifiedNoSpilling.kt"); + } + @TestMetadata("linenumberForOneParametersArgumentCall.kt") public void testLinenumberForOneParametersArgumentCall() throws Exception { runTest("compiler/testData/codegen/bytecodeText/inline/linenumberForOneParametersArgumentCall.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/IrBytecodeTextTestGenerated.java index d5215136993..f0678413a95 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/IrBytecodeTextTestGenerated.java @@ -1978,6 +1978,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/inline/inlineReturnsNothing3.kt"); } + @TestMetadata("inlineSuspendReifiedNoSpilling.kt") + public void testInlineSuspendReifiedNoSpilling() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/inline/inlineSuspendReifiedNoSpilling.kt"); + } + @TestMetadata("linenumberForOneParametersArgumentCall.kt") public void testLinenumberForOneParametersArgumentCall() throws Exception { runTest("compiler/testData/codegen/bytecodeText/inline/linenumberForOneParametersArgumentCall.kt");