Do not mark fake inliner variables as alive
This prevents them from spilling. #KT-29317 Fixed
This commit is contained in:
committed by
Stanislav Erokhin
parent
7e4e1b9a4d
commit
e8c52e0a8f
+2
-9
@@ -498,12 +498,6 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
val frames = performRefinedTypeAnalysis(methodNode, containingClassInternalName)
|
val frames = performRefinedTypeAnalysis(methodNode, containingClassInternalName)
|
||||||
fun AbstractInsnNode.index() = instructions.indexOf(this)
|
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
|
// We postpone these actions because they change instruction indices that we use when obtaining frames
|
||||||
val postponedActions = mutableListOf<() -> Unit>()
|
val postponedActions = mutableListOf<() -> Unit>()
|
||||||
val maxVarsCountByType = mutableMapOf<Type, Int>()
|
val maxVarsCountByType = mutableMapOf<Type, Int>()
|
||||||
@@ -545,9 +539,8 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
// k + 2 - exception
|
// k + 2 - exception
|
||||||
val variablesToSpill =
|
val variablesToSpill =
|
||||||
(0 until localsCount)
|
(0 until localsCount)
|
||||||
.filterNot {
|
.filterNot { it in setOf(continuationIndex, dataIndex, exceptionIndex) }
|
||||||
it in setOf(continuationIndex, dataIndex, exceptionIndex) || it.isInlinerFakeVariable(suspensionCallBegin.index())
|
.map { Pair(it, frame.getLocal(it)) }
|
||||||
}.map { Pair(it, frame.getLocal(it)) }
|
|
||||||
.filter { (index, value) ->
|
.filter { (index, value) ->
|
||||||
(index == 0 && needDispatchReceiver && isForNamedFunction) ||
|
(index == 0 && needDispatchReceiver && isForNamedFunction) ||
|
||||||
(value != StrictBasicValue.UNINITIALIZED_VALUE && livenessFrame.isAlive(index))
|
(value != StrictBasicValue.UNINITIALIZED_VALUE && livenessFrame.isAlive(index))
|
||||||
|
|||||||
+6
-3
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.codegen.optimization.common
|
package org.jetbrains.kotlin.codegen.optimization.common
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
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.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.IincInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.IincInsnNode
|
||||||
@@ -78,11 +79,13 @@ private fun useVar(
|
|||||||
) {
|
) {
|
||||||
val index = node.instructions.indexOf(insn)
|
val index = node.instructions.indexOf(insn)
|
||||||
node.localVariables.filter {
|
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
|
Type.getType(it.desc).sort == typeAnnotatedFrame?.getLocal(it.index)?.type?.sort
|
||||||
}.forEach {
|
}.forEach {
|
||||||
frame.markAlive(it.index)
|
frame.markAlive(it.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (insn is VarInsnNode && insn.isLoadOperation()) {
|
if (insn is VarInsnNode && insn.isLoadOperation()) {
|
||||||
frame.markAlive(insn.`var`)
|
frame.markAlive(insn.`var`)
|
||||||
|
|||||||
+25
@@ -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 <reified Type : Any> 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
|
||||||
@@ -1978,6 +1978,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/inline/inlineReturnsNothing3.kt");
|
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")
|
@TestMetadata("linenumberForOneParametersArgumentCall.kt")
|
||||||
public void testLinenumberForOneParametersArgumentCall() throws Exception {
|
public void testLinenumberForOneParametersArgumentCall() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/inline/linenumberForOneParametersArgumentCall.kt");
|
runTest("compiler/testData/codegen/bytecodeText/inline/linenumberForOneParametersArgumentCall.kt");
|
||||||
|
|||||||
@@ -1978,6 +1978,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/inline/inlineReturnsNothing3.kt");
|
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")
|
@TestMetadata("linenumberForOneParametersArgumentCall.kt")
|
||||||
public void testLinenumberForOneParametersArgumentCall() throws Exception {
|
public void testLinenumberForOneParametersArgumentCall() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/inline/linenumberForOneParametersArgumentCall.kt");
|
runTest("compiler/testData/codegen/bytecodeText/inline/linenumberForOneParametersArgumentCall.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user