Add $completion entry to suspend functions' LVT
#KT-28810 Fixed
This commit is contained in:
+33
-7
@@ -49,6 +49,8 @@ private const val COROUTINES_METADATA_METHOD_NAME_JVM_NAME = "m"
|
||||
private const val COROUTINES_METADATA_CLASS_NAME_JVM_NAME = "c"
|
||||
private const val COROUTINES_METADATA_VERSION_JVM_NAME = "v"
|
||||
|
||||
const val SUSPEND_FUNCTION_CONTINUATION_PARAMETER = "\$completion"
|
||||
|
||||
class CoroutineTransformerMethodVisitor(
|
||||
delegate: MethodVisitor,
|
||||
access: Int,
|
||||
@@ -105,6 +107,8 @@ class CoroutineTransformerMethodVisitor(
|
||||
if (isForNamedFunction) {
|
||||
ReturnUnitMethodTransformer.transform(containingClassInternalName, methodNode)
|
||||
|
||||
addCompletionParameterToLVT(methodNode)
|
||||
|
||||
if (allSuspensionPointsAreTailCalls(containingClassInternalName, methodNode, suspensionPoints)) {
|
||||
dropSuspensionMarkers(methodNode, suspensionPoints)
|
||||
return
|
||||
@@ -197,6 +201,32 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCompletionParameterToLVT(methodNode: MethodNode) {
|
||||
val index =
|
||||
/* all args */ Type.getMethodType(methodNode.desc).argumentTypes.fold(0) { a, b -> a + b.size } +
|
||||
/* this */ (if (isStatic(methodNode.access)) 0 else 1) -
|
||||
/* only last */ 1
|
||||
val startLabel = with(methodNode.instructions) {
|
||||
if (first is LabelNode) first as LabelNode
|
||||
else LabelNode().also { insertBefore(first, it) }
|
||||
}
|
||||
|
||||
val endLabel = with(methodNode.instructions) {
|
||||
if (last is LabelNode) last as LabelNode
|
||||
else LabelNode().also { insert(last, it) }
|
||||
}
|
||||
methodNode.localVariables.add(
|
||||
LocalVariableNode(
|
||||
SUSPEND_FUNCTION_CONTINUATION_PARAMETER,
|
||||
languageVersionSettings.continuationAsmType().descriptor,
|
||||
null,
|
||||
startLabel,
|
||||
endLabel,
|
||||
index
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun findSuspensionPointLineNumber(suspensionPoint: SuspensionPoint) =
|
||||
suspensionPoint.suspensionCallBegin.findPreviousOrNull { it is LineNumberNode } as LineNumberNode?
|
||||
|
||||
@@ -238,15 +268,11 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
|
||||
private fun fixLvtForParameters(methodNode: MethodNode, startLabel: LabelNode, endLabel: LabelNode) {
|
||||
// We need to skip continuation, since the inliner likes to remap variables there.
|
||||
// But this is not a problem, since we have separate $continuation LVT entry
|
||||
|
||||
val paramsNum =
|
||||
/* this */ (if (internalNameForDispatchReceiver != null) 1 else 0) +
|
||||
/* real params */ Type.getArgumentTypes(methodNode.desc).size -
|
||||
/* no continuation */ if (isForNamedFunction) 1 else 0
|
||||
/* this */ (if (isStatic(methodNode.access)) 0 else 1) +
|
||||
/* real params */ Type.getArgumentTypes(methodNode.desc).fold(0) { a, b -> a + b.size }
|
||||
|
||||
for (i in 0..paramsNum) {
|
||||
for (i in 0 until paramsNum) {
|
||||
fixRangeOfLvtRecord(methodNode, i, startLabel, endLabel)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.common
|
||||
|
||||
import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_FUNCTION_CONTINUATION_PARAMETER
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -80,7 +81,7 @@ private fun useVar(
|
||||
val index = node.instructions.indexOf(insn)
|
||||
node.localVariables.filter {
|
||||
// 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) &&
|
||||
!it.name.isInvisibleDebuggerVariable() &&
|
||||
node.instructions.indexOf(it.start) < index && index < node.instructions.indexOf(it.end) &&
|
||||
Type.getType(it.desc).sort == typeAnnotatedFrame?.getLocal(it.index)?.type?.sort
|
||||
}.forEach {
|
||||
@@ -93,3 +94,8 @@ private fun useVar(
|
||||
frame.markAlive(insn.`var`)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.isInvisibleDebuggerVariable(): Boolean =
|
||||
startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT) ||
|
||||
startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) ||
|
||||
this == SUSPEND_FUNCTION_CONTINUATION_PARAMETER
|
||||
|
||||
Reference in New Issue
Block a user