JVM: Fix local variable ranges in state machine transform.
When a suspension point is inlined, the inlining local spans unspilling code where the local slot has not been initialized. The transformer already inserted initialization code for the local, however, it did not split the local variable table. Therefore, the inlining local is defined on instructions where the local slot has no value (namely the instructions that initialize the local slot on the unspilling path). This change adds splitting of the local variable table as well. When updating to a new version of D8, the uninitialized local slot showed up. D8 will repair it in this case, but it is better to not generate such code.
This commit is contained in:
+19
-1
@@ -201,20 +201,38 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
// When suspension point is inlined, it is in range of fake inliner variables.
|
||||
// Path from TABLESWITCH into unspilling goes to latter part of the range.
|
||||
// In this case the variables are uninitialized, initialize them
|
||||
// In this case the variables are uninitialized, initialize them, and split the local variable
|
||||
// range so that the local variable is only defined when initialized.
|
||||
private fun initializeFakeInlinerVariables(methodNode: MethodNode, stateLabels: List<LabelNode>) {
|
||||
for (stateLabel in stateLabels) {
|
||||
val newRecords = mutableListOf<LocalVariableNode>()
|
||||
for (record in methodNode.localVariables) {
|
||||
if (isFakeLocalVariableForInline(record.name) &&
|
||||
methodNode.instructions.indexOf(record.start) < methodNode.instructions.indexOf(stateLabel) &&
|
||||
methodNode.instructions.indexOf(stateLabel) < methodNode.instructions.indexOf(record.end)
|
||||
) {
|
||||
val newEnd = record.end
|
||||
val newStart = LabelNode()
|
||||
record.end = stateLabel
|
||||
methodNode.instructions.insert(stateLabel, withInstructionAdapter {
|
||||
iconst(0)
|
||||
store(record.index, Type.INT_TYPE)
|
||||
}.also {
|
||||
it.add(newStart)
|
||||
})
|
||||
newRecords.add(
|
||||
LocalVariableNode(
|
||||
record.name,
|
||||
record.desc,
|
||||
record.signature,
|
||||
newStart,
|
||||
newEnd,
|
||||
record.index
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
methodNode.localVariables.addAll(newRecords)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user