Initialize fake inliner variables on resume path
Otherwise, this will cause R8 to complain.
This commit is contained in:
+31
-8
@@ -141,8 +141,9 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
|
|
||||||
val suspensionPointLineNumbers = suspensionPoints.map { findSuspensionPointLineNumber(it) }
|
val suspensionPointLineNumbers = suspensionPoints.map { findSuspensionPointLineNumber(it) }
|
||||||
|
|
||||||
val continuationLabels = suspensionPoints.withIndex().map {
|
// Create states in state-machine, to which state-machine can jump
|
||||||
transformCallAndReturnContinuationLabel(
|
val stateLabels = suspensionPoints.withIndex().map {
|
||||||
|
transformCallAndReturnStateLabel(
|
||||||
it.index + 1, it.value, methodNode, suspendMarkerVarIndex, suspensionPointLineNumbers[it.index]
|
it.index + 1, it.value, methodNode, suspendMarkerVarIndex, suspensionPointLineNumbers[it.index]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -167,7 +168,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
0,
|
0,
|
||||||
suspensionPoints.size,
|
suspensionPoints.size,
|
||||||
defaultLabel,
|
defaultLabel,
|
||||||
firstStateLabel, *continuationLabels.toTypedArray()
|
firstStateLabel, *stateLabels.toTypedArray()
|
||||||
),
|
),
|
||||||
firstStateLabel
|
firstStateLabel
|
||||||
)
|
)
|
||||||
@@ -184,6 +185,8 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initializeFakeInlinerVariables(methodNode, stateLabels)
|
||||||
|
|
||||||
dropSuspensionMarkers(methodNode)
|
dropSuspensionMarkers(methodNode)
|
||||||
methodNode.removeEmptyCatchBlocks()
|
methodNode.removeEmptyCatchBlocks()
|
||||||
|
|
||||||
@@ -192,6 +195,26 @@ 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
|
||||||
|
private fun initializeFakeInlinerVariables(methodNode: MethodNode, stateLabels: List<LabelNode>) {
|
||||||
|
for (stateLabel in stateLabels) {
|
||||||
|
val unitializedFakeInlinerVariables = arrayListOf<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)
|
||||||
|
) {
|
||||||
|
methodNode.instructions.insert(stateLabel, withInstructionAdapter {
|
||||||
|
iconst(0)
|
||||||
|
store(record.index, Type.INT_TYPE)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun addCompletionParameterToLVT(methodNode: MethodNode) {
|
private fun addCompletionParameterToLVT(methodNode: MethodNode) {
|
||||||
val index =
|
val index =
|
||||||
/* all args */ Type.getMethodType(methodNode.desc).argumentTypes.fold(0) { a, b -> a + b.size } +
|
/* all args */ Type.getMethodType(methodNode.desc).argumentTypes.fold(0) { a, b -> a + b.size } +
|
||||||
@@ -819,14 +842,14 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
return suspensionCallEnd.next as LabelNode
|
return suspensionCallEnd.next as LabelNode
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformCallAndReturnContinuationLabel(
|
private fun transformCallAndReturnStateLabel(
|
||||||
id: Int,
|
id: Int,
|
||||||
suspension: SuspensionPoint,
|
suspension: SuspensionPoint,
|
||||||
methodNode: MethodNode,
|
methodNode: MethodNode,
|
||||||
suspendMarkerVarIndex: Int,
|
suspendMarkerVarIndex: Int,
|
||||||
suspendPointLineNumber: LineNumberNode?
|
suspendPointLineNumber: LineNumberNode?
|
||||||
): LabelNode {
|
): LabelNode {
|
||||||
val continuationLabel = LabelNode().linkWithLabel()
|
val stateLabel = LabelNode().linkWithLabel()
|
||||||
val continuationLabelAfterLoadedResult = LabelNode()
|
val continuationLabelAfterLoadedResult = LabelNode()
|
||||||
val suspendElementLineNumber = lineNumber
|
val suspendElementLineNumber = lineNumber
|
||||||
var nextLineNumberNode = nextDefinitelyHitLineNumber(suspension)
|
var nextLineNumberNode = nextDefinitelyHitLineNumber(suspension)
|
||||||
@@ -854,7 +877,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
load(suspendMarkerVarIndex, AsmTypes.OBJECT_TYPE)
|
load(suspendMarkerVarIndex, AsmTypes.OBJECT_TYPE)
|
||||||
areturn(AsmTypes.OBJECT_TYPE)
|
areturn(AsmTypes.OBJECT_TYPE)
|
||||||
// Mark place for continuation
|
// Mark place for continuation
|
||||||
visitLabel(continuationLabel.label)
|
visitLabel(stateLabel.label)
|
||||||
})
|
})
|
||||||
|
|
||||||
// After suspension point there is always three nodes: L1, NOP, L2
|
// After suspension point there is always three nodes: L1, NOP, L2
|
||||||
@@ -905,7 +928,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return continuationLabel
|
return stateLabel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the next line number instruction that is defintely hit. That is, a line number
|
// Find the next line number instruction that is defintely hit. That is, a line number
|
||||||
@@ -1175,7 +1198,7 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (variable in oldLvt) {
|
for (variable in oldLvt) {
|
||||||
// $completion, $continuation and $result are dead, but they are used by debugger, as well as fake inliner variables
|
// $continuation and $result are dead, but they are used by debugger, as well as fake inliner variables
|
||||||
// For example, $continuation is used to create async stack trace
|
// For example, $continuation is used to create async stack trace
|
||||||
if (variable.name == CONTINUATION_VARIABLE_NAME ||
|
if (variable.name == CONTINUATION_VARIABLE_NAME ||
|
||||||
variable.name == SUSPEND_CALL_RESULT_NAME ||
|
variable.name == SUSPEND_CALL_RESULT_NAME ||
|
||||||
|
|||||||
+2
-1
@@ -17,7 +17,8 @@ suspend fun ApplicationCall.test(authenticationService: AuthenticationService) {
|
|||||||
respond(authenticationService.execute(receiveJSON()))
|
respond(authenticationService.execute(receiveJSON()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2 ISTORE 5
|
// $i$f$respond x1, $i$f$receiveJSON x2: before and after suspension point
|
||||||
|
// 3 ISTORE 5
|
||||||
// 0 ILOAD 5
|
// 0 ILOAD 5
|
||||||
// 1 \$i\$f\$receiveJSON I .* 5
|
// 1 \$i\$f\$receiveJSON I .* 5
|
||||||
// 1 \$i\$f\$respond I .* 5
|
// 1 \$i\$f\$respond I .* 5
|
||||||
|
|||||||
Reference in New Issue
Block a user