JVM: remove InlineOnlySmapSkipper

1. the class didn't make much sense anyway;
2. the same code is useful for default lambdas, which can also have
   a line number equal to the call site.
This commit is contained in:
pyos
2022-04-01 10:23:00 +02:00
committed by max-kammerer
parent 9220d47594
commit db62640ae2
5 changed files with 41 additions and 41 deletions
@@ -335,8 +335,7 @@ class AnonymousObjectTransformer(
inliningContext.callSiteInfo.inlineScopeVisibility,
inliningContext.callSiteInfo.file,
inliningContext.callSiteInfo.lineNumber
),
null
)
).doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, mapOf())
reifiedTypeParametersUsages?.let(result.reifiedTypeParametersUsages::mergeAll)
deferringVisitor.visitMaxs(-1, -1)
@@ -106,7 +106,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
node, parameters, info, FieldRemapper(null, null, parameters), sourceCompiler.isCallInsideSameModuleAsCallee,
"Method inlining " + sourceCompiler.callElementText,
SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, callSite),
info.callSiteInfo, if (isInlineOnly) InlineOnlySmapSkipper(codegen) else null,
info.callSiteInfo, isInlineOnly,
!isInlinedToInlineFunInKotlinRuntime()
) //with captured
@@ -48,7 +48,7 @@ class MethodInliner(
private val errorPrefix: String,
private val sourceMapper: SourceMapCopier,
private val inlineCallSiteInfo: InlineCallSiteInfo,
private val inlineOnlySmapSkipper: InlineOnlySmapSkipper?, //non null only for root
private val overrideLineNumber: Boolean = false,
private val shouldPreprocessApiVersionCalls: Boolean = false
) {
private val languageVersionSettings = inliningContext.state.languageVersionSettings
@@ -154,9 +154,17 @@ class MethodInliner(
val fakeContinuationName = CoroutineTransformer.findFakeContinuationConstructorClassName(node)
val markerShift = calcMarkerShift(parameters, node)
var currentLineNumber = if (overrideLineNumber) sourceMapper.callSite!!.line else -1
val lambdaInliner = object : InlineAdapter(remappingMethodAdapter, parameters.argsSizeOnStack, sourceMapper) {
private var transformationInfo: TransformationInfo? = null
override fun visitLineNumber(line: Int, start: Label) {
if (!overrideLineNumber) {
currentLineNumber = line
}
super.visitLineNumber(line, start)
}
private fun handleAnonymousObjectRegeneration() {
transformationInfo = iterator.next()
@@ -250,10 +258,29 @@ class MethodInliner(
store(valueParamShift, type)
}
if (expectedParameters.isEmpty()) {
nop() // add something for a line number to bind onto
nop() // add something for a line number to bind onto (TODO what line number?)
}
val firstLine = info.node.node.instructions.asSequence().mapNotNull { it as? LineNumberNode }.firstOrNull()?.line ?: -1
if (currentLineNumber >= 0 && firstLine == currentLineNumber) {
// This can happen in two cases:
// 1. `someInlineOnlyFunction { singleLineLambda }`: in this case line numbers are removed
// from the inline function, so the entirety of its bytecode has the line number of
// the call site;
// 2. `inline fun someFunction(defaultLambda: ... = { ... }) = singleLineExpression`:
// all of `someFunction`, including `defaultLambda` if no value is provided at call site,
// has the line number of the declaration.
// In those cases the debugger is unable to observe the boundary between the body of the function
// and the inline lambda call, as they have the exact same line number. So to force a JDI
// event we insert a fake line number separating those two real stretches. The event corresponding
// to the fake line number itself should be ignored by the debugger though.
val label = Label()
val fakeLineNumber =
sourceMapper.parent.mapSyntheticLineNumber(SourceMapper.LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER)
mv.visitLabel(label)
mv.visitLineNumber(fakeLineNumber, label)
}
inlineOnlySmapSkipper?.onInlineLambdaStart(remappingMethodAdapter, info.node.node, sourceMapper.parent)
addInlineMarker(this, true)
val lambdaParameters = info.addAllParameters(nodeRemapper)
@@ -270,7 +297,7 @@ class MethodInliner(
newCapturedRemapper,
if (info is DefaultLambda) isSameModule else true /*cause all nested objects in same module as lambda*/,
"Lambda inlining " + info.lambdaClassType.internalName,
SourceMapCopier(sourceMapper.parent, info.node.classSMAP, callSite), inlineCallSiteInfo, null
SourceMapCopier(sourceMapper.parent, info.node.classSMAP, callSite), inlineCallSiteInfo
)
val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift)
@@ -284,7 +311,12 @@ class MethodInliner(
StackValue.coerce(info.invokeMethod.returnType, info.invokeMethodReturnType, OBJECT_TYPE, nullableAnyType, this)
setLambdaInlining(false)
addInlineMarker(this, false)
inlineOnlySmapSkipper?.onInlineLambdaEnd(remappingMethodAdapter)
if (overrideLineNumber) {
val endLabel = Label()
mv.visitLabel(endLabel)
mv.visitLineNumber(currentLineNumber, endLabel)
}
} else if (isAnonymousConstructorCall(owner, name)) { //TODO add method
//TODO add proper message
val newInfo = transformationInfo as? AnonymousObjectTransformationInfo ?: throw AssertionError(
@@ -371,7 +403,7 @@ class MethodInliner(
)
val transformationVisitor = object : InlineMethodInstructionAdapter(transformedNode) {
private val GENERATE_DEBUG_INFO = GENERATE_SMAP && inlineOnlySmapSkipper == null
private val GENERATE_DEBUG_INFO = GENERATE_SMAP && !overrideLineNumber
private val isInliningLambda = nodeRemapper.isInsideInliningLambda
@@ -87,6 +87,7 @@ class SourceMapper(val sourceInfo: SourceInfo?) {
companion object {
const val FAKE_FILE_NAME = "fake.kt"
const val FAKE_PATH = "kotlin/jvm/internal/FakeKt"
const val LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER = 1
}
init {
@@ -9,7 +9,6 @@ import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.ASSERTIONS_DISABLED_FIELD_NAME
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.BaseExpressionCodegen
import org.jetbrains.kotlin.codegen.SamWrapperCodegen.SAM_WRAPPER_SUFFIX
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
@@ -695,37 +694,6 @@ fun isFakeLocalVariableForInline(name: String): Boolean {
internal fun isThis0(name: String): Boolean = AsmUtil.CAPTURED_THIS_FIELD == name
class InlineOnlySmapSkipper(codegen: BaseExpressionCodegen) {
private val callLineNumber = codegen.lastLineNumber
companion object {
const val LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER = 1
}
fun onInlineLambdaStart(mv: MethodVisitor, lambda: MethodNode, smap: SourceMapper) {
val firstLine = lambda.instructions.asSequence().mapNotNull { it as? LineNumberNode }.firstOrNull()?.line ?: -1
if (callLineNumber >= 0 && firstLine == callLineNumber) {
// We want the debugger to be able to break both on the inline call itself, plus on each
// invocation of the inline lambda passed to it. For that to happen there needs to be at least
// one different line number in between those breakpoints for the VM to emit a locatable event.
// @InlineOnly functions, however, contain no line numbers, so if the lambda is single-line,
// the entire call will "meld" into a single region. To break it up, we insert a different line
// number that is remapped by the SMAP to a line that does not exist.
val label = Label()
mv.visitLabel(label)
mv.visitLineNumber(smap.mapSyntheticLineNumber(LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER), label)
}
}
fun onInlineLambdaEnd(mv: MethodVisitor) {
if (callLineNumber >= 0) {
val label = Label()
mv.visitLabel(label)
mv.visitLineNumber(callLineNumber, label)
}
}
}
fun MethodNode.preprocessSuspendMarkers(forInline: Boolean, keepFakeContinuation: Boolean = true) {
if (instructions.first == null) return
if (!keepFakeContinuation) {