in jvm-agent/src/main/org/jetbrains/lincheck/jvm/agent/transformers/InlineMethodCallTransformer.kt [80:117]
override fun visitLabel(label: Label) {
if (!methodInfo.locals.hasInlines || looksLikeSuspendMethod || looksLikeBlocklistedMethod) {
super.visitLabel(label)
return
}
// It is not clear, could one label be used to mark the end of one inline call and
// the start of another one. Nothing wrong instrument exists first.
while (inlineStack.isNotEmpty()) {
val (lvar, methodId, tryEndsCatchBeginsLabel, savedInlineDepth) = inlineStack.last()
val cmp = methodInfo.labels.compare(lvar.endLabel, label)
if (cmp > 0) break
if (cmp < 0) {
Logger.warn { "${className}.${methodName}: Inline call to ${lvar.inlineMethodName} should be finished at label ${lvar.endLabel} but still alive at ${label}." }
}
emitInlinedMethodEpilogue(methodId, tryEndsCatchBeginsLabel)
inlineStack.removeLast()
currentInlineDepth = savedInlineDepth
}
// Visit the label itself
super.visitLabel(label)
// Can one start label mark the beginning of several inlined methods?
// One end label can mark several returns for sure.
// Support multiple starts to be sure.
// Sort starts by end labels (it provides proper nesting) and then variable slots (it provides stable sort)
for (lvar in methodInfo.locals.inlinesStartAt(label)
.filter { it.inlineMethodName != methodName && isSupportedInline(it) }
.sortedWith(localVarInlineStartComparator)
) {
// This cannot be inserted into `.filter` above because top-of-stack can change in this loop
if (isNakedLambda(lvar)) continue
inlineStack.add(
emitInlineMethodPrologue(lvar)
)
}
}