Do not just merge consequent LVT ranges, but also extend them
This commit is contained in:
committed by
TeamCityServer
parent
8d764fa50e
commit
ebb340fe68
+47
-31
@@ -192,7 +192,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
dropUnboxInlineClassMarkers(methodNode, suspensionPoints)
|
||||
methodNode.removeEmptyCatchBlocks()
|
||||
|
||||
updateLvtAccordingToLiveness(methodNode, isForNamedFunction)
|
||||
updateLvtAccordingToLiveness(methodNode, isForNamedFunction, stateLabels)
|
||||
|
||||
if (languageVersionSettings.isReleaseCoroutines()) {
|
||||
writeDebugMetadata(methodNode, suspensionPointLineNumbers, spilledToVariableMapping)
|
||||
@@ -1269,7 +1269,7 @@ private fun MethodNode.nodeTextWithLiveness(liveness: List<VariableLivenessFrame
|
||||
* This means, that function parameters do not longer span the whole function, including `this`.
|
||||
* This might and will break some bytecode processors, including old versions of R8. See KT-24510.
|
||||
*/
|
||||
private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction: Boolean) {
|
||||
private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction: Boolean, suspensionPoints: List<LabelNode>) {
|
||||
val liveness = analyzeLiveness(method)
|
||||
|
||||
fun List<LocalVariableNode>.findRecord(insnIndex: Int, variableIndex: Int): LocalVariableNode? {
|
||||
@@ -1288,8 +1288,8 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
||||
fun nextLabel(node: AbstractInsnNode?): LabelNode? {
|
||||
var current = node
|
||||
while (current != null) {
|
||||
if (current is LabelNode) return current as LabelNode
|
||||
current = current!!.next
|
||||
if (current is LabelNode) return current
|
||||
current = current.next
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -1346,33 +1346,17 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
||||
|
||||
// Attempt to extend existing local variable node corresponding to the record in
|
||||
// the original local variable table, if there is no back-edge
|
||||
val recordToExtend: LocalVariableNode? = oldLvtNodeToLatestNewLvtNode[lvtRecord]
|
||||
var recordExtended = false
|
||||
if (recordToExtend != null) {
|
||||
var hasBackEdgeOrStore = false
|
||||
var current: AbstractInsnNode? = recordToExtend.end
|
||||
while (current != null && current != endLabel) {
|
||||
if (current is JumpInsnNode) {
|
||||
if (method.instructions.indexOf((current as JumpInsnNode).label) < method.instructions.indexOf(current)) {
|
||||
hasBackEdgeOrStore = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (current!!.isStoreOperation() && (current as VarInsnNode).`var` == recordToExtend.index) {
|
||||
hasBackEdgeOrStore = true
|
||||
break
|
||||
}
|
||||
current = current!!.next
|
||||
}
|
||||
if (!hasBackEdgeOrStore) {
|
||||
recordToExtend.end = endLabel
|
||||
recordExtended = true
|
||||
}
|
||||
}
|
||||
if (!recordExtended) {
|
||||
val node = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
|
||||
method.localVariables.add(node)
|
||||
oldLvtNodeToLatestNewLvtNode[lvtRecord] = node
|
||||
val latest = oldLvtNodeToLatestNewLvtNode[lvtRecord]
|
||||
// if we can extend the previous range to where the local variable dies, we do not need a
|
||||
// new entry, we know we cannot extend it to the lvt.endOffset, if we could we would have
|
||||
// done so when we added it below.
|
||||
val extended = latest?.extendRecordIfPossible(method, suspensionPoints, lvtRecord.end) ?: false
|
||||
if (!extended) {
|
||||
val new = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
|
||||
oldLvtNodeToLatestNewLvtNode[lvtRecord] = new
|
||||
method.localVariables.add(new)
|
||||
// see if we can extend it all the way to the old end
|
||||
new.extendRecordIfPossible(method, suspensionPoints, lvtRecord.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1395,3 +1379,35 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We cannot extend a record if there is STORE instruction or a back-edge.
|
||||
* STORE instructions can signify a unspilling operation, in which case, the variable will become visible before it unspilled,
|
||||
* back-edges occur in loops.
|
||||
*
|
||||
* @return true if the range has been extended
|
||||
*/
|
||||
private fun LocalVariableNode.extendRecordIfPossible(
|
||||
method: MethodNode,
|
||||
suspensionPoints: List<LabelNode>,
|
||||
endLabel: LabelNode
|
||||
): Boolean {
|
||||
val nextSuspensionPointLabel = suspensionPoints.find { it in InsnSequence(end, endLabel) } ?: endLabel
|
||||
|
||||
var current: AbstractInsnNode? = end
|
||||
while (current != null && current != nextSuspensionPointLabel) {
|
||||
if (current is JumpInsnNode) {
|
||||
if (method.instructions.indexOf(current.label) < method.instructions.indexOf(current)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// TODO: HACK
|
||||
// TODO: Find correct label, which is OK to be used as end label.
|
||||
if (current.opcode == Opcodes.ARETURN && nextSuspensionPointLabel != endLabel) return false
|
||||
if (current.isStoreOperation() && (current as VarInsnNode).`var` == index) {
|
||||
return false
|
||||
}
|
||||
current = current.next
|
||||
}
|
||||
end = nextSuspensionPointLabel
|
||||
return true
|
||||
}
|
||||
|
||||
+6
-1
@@ -15,6 +15,11 @@ fun main(args: Array<String>) {
|
||||
suspend fun SequenceScope<Int>.awaitSeq(): Int = 42
|
||||
|
||||
// 1 LINENUMBER 9 L18
|
||||
// 1 LOCALVARIABLE a I L[0-9]+ L17
|
||||
|
||||
// JVM_IR_TEMPLATES
|
||||
// 1 LOCALVARIABLE a I L[0-9]+ L4
|
||||
|
||||
// JVM_TEMPLATES
|
||||
// 1 LOCALVARIABLE a I L[0-9]+ L18
|
||||
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
|
||||
+1
-1
@@ -36,6 +36,6 @@ suspend fun box() {
|
||||
// test.kt:5 foo: $completion:kotlin.coroutines.Continuation=A$foo1$1
|
||||
// test.kt:8 foo1: $continuation:kotlin.coroutines.Continuation=A$foo1$1, $result:java.lang.Object=null, l:long=42:long
|
||||
// test.kt:9 foo1: $continuation:kotlin.coroutines.Continuation=A$foo1$1, $result:java.lang.Object=null, l:long=42:long
|
||||
// test.kt:10 foo1: $continuation:kotlin.coroutines.Continuation=A$foo1$1, $result:java.lang.Object=null
|
||||
// test.kt:10 foo1: $continuation:kotlin.coroutines.Continuation=A$foo1$1, $result:java.lang.Object=null, l:long=42:long
|
||||
// test.kt:14 box: $completion:kotlin.coroutines.Continuation=helpers.ResultContinuation
|
||||
// test.kt:15 box: $completion:kotlin.coroutines.Continuation=helpers.ResultContinuation
|
||||
|
||||
+1
-1
@@ -32,6 +32,6 @@ suspend fun box() {
|
||||
// test.kt:4 foo: $completion:kotlin.coroutines.Continuation=TestKt$foo1$1
|
||||
// test.kt:7 foo1: $continuation:kotlin.coroutines.Continuation=TestKt$foo1$1, $result:java.lang.Object=null, l:long=42:long
|
||||
// test.kt:8 foo1: $continuation:kotlin.coroutines.Continuation=TestKt$foo1$1, $result:java.lang.Object=null, l:long=42:long
|
||||
// test.kt:9 foo1: $continuation:kotlin.coroutines.Continuation=TestKt$foo1$1, $result:java.lang.Object=null
|
||||
// test.kt:9 foo1: $continuation:kotlin.coroutines.Continuation=TestKt$foo1$1, $result:java.lang.Object=null, l:long=42:long
|
||||
// test.kt:12 box: $completion:kotlin.coroutines.Continuation=helpers.ResultContinuation
|
||||
// test.kt:13 box: $completion:kotlin.coroutines.Continuation=helpers.ResultContinuation
|
||||
|
||||
+1
-1
@@ -36,6 +36,6 @@ suspend fun box() {
|
||||
// test.kt:6 foo: $this$foo:A=A, $completion:kotlin.coroutines.Continuation=TestKt$foo1$1
|
||||
// test.kt:9 foo1: $continuation:kotlin.coroutines.Continuation=TestKt$foo1$1, $result:java.lang.Object=null, l:long=42:long
|
||||
// test.kt:10 foo1: $continuation:kotlin.coroutines.Continuation=TestKt$foo1$1, $result:java.lang.Object=null, l:long=42:long
|
||||
// test.kt:11 foo1: $continuation:kotlin.coroutines.Continuation=TestKt$foo1$1, $result:java.lang.Object=null
|
||||
// test.kt:11 foo1: $continuation:kotlin.coroutines.Continuation=TestKt$foo1$1, $result:java.lang.Object=null, l:long=42:long
|
||||
// test.kt:14 box: $completion:kotlin.coroutines.Continuation=helpers.ResultContinuation
|
||||
// test.kt:15 box: $completion:kotlin.coroutines.Continuation=helpers.ResultContinuation
|
||||
|
||||
@@ -45,7 +45,7 @@ suspend fun box() {
|
||||
// test.kt:15 box: $continuation:kotlin.coroutines.Continuation=TestKt$box$1, $result:java.lang.Object=null, $i$f$suspendBar:int=0:int, $this$extensionFun$iv$iv:AtomicInt=AtomicInt, $i$f$extensionFun:int=0:int
|
||||
// test.kt:6 getValue:
|
||||
// test.kt:15 box: $continuation:kotlin.coroutines.Continuation=TestKt$box$1, $result:java.lang.Object=null, $i$f$suspendBar:int=0:int, $this$extensionFun$iv$iv:AtomicInt=AtomicInt, $i$f$extensionFun:int=0:int
|
||||
// test.kt:16 box: $continuation:kotlin.coroutines.Continuation=TestKt$box$1, $result:java.lang.Object=null, $i$f$suspendBar:int=0:int, $i$f$extensionFun:int=0:int
|
||||
// test.kt:16 box: $continuation:kotlin.coroutines.Continuation=TestKt$box$1, $result:java.lang.Object=null, $i$f$suspendBar:int=0:int, $this$extensionFun$iv$iv:AtomicInt=AtomicInt, $i$f$extensionFun:int=0:int
|
||||
// test.kt:20 box: $continuation:kotlin.coroutines.Continuation=TestKt$box$1, $result:java.lang.Object=null, $i$f$suspendBar:int=0:int
|
||||
// test.kt:21 box: $continuation:kotlin.coroutines.Continuation=TestKt$box$1, $result:java.lang.Object=null, $i$f$suspendBar:int=0:int, $i$a$-suspendCoroutineUninterceptedOrReturn-TestKt$suspendBar$2$iv:int=0:int
|
||||
// test.kt:22 box: $continuation:kotlin.coroutines.Continuation=TestKt$box$1, $result:java.lang.Object=null, $i$f$suspendBar:int=0:int, $i$a$-suspendCoroutineUninterceptedOrReturn-TestKt$suspendBar$2$iv:int=0:int
|
||||
|
||||
@@ -45,7 +45,7 @@ suspend fun box() = foo(A()) { (x_param, _, y_param) ->
|
||||
// test.kt:12 invokeSuspend: $result:java.lang.Object=kotlin.Unit, $dstr$x_param$_u24__u24$y_param:A=A, x_param:java.lang.String="O":java.lang.String
|
||||
|
||||
// LOCAL VARIABLES
|
||||
// test.kt:13 invokeSuspend: $result:java.lang.Object=kotlin.Unit, x_param:java.lang.String="O":java.lang.String, y_param:java.lang.String="K":java.lang.String
|
||||
// test.kt:13 invokeSuspend: $result:java.lang.Object=kotlin.Unit, $dstr$x_param$_u24__u24$y_param:A=A, x_param:java.lang.String="O":java.lang.String, y_param:java.lang.String="K":java.lang.String
|
||||
|
||||
// LOCAL VARIABLES JVM
|
||||
// test.kt:-1 invoke:
|
||||
|
||||
Reference in New Issue
Block a user