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:
+1
-2
@@ -335,8 +335,7 @@ class AnonymousObjectTransformer(
|
|||||||
inliningContext.callSiteInfo.inlineScopeVisibility,
|
inliningContext.callSiteInfo.inlineScopeVisibility,
|
||||||
inliningContext.callSiteInfo.file,
|
inliningContext.callSiteInfo.file,
|
||||||
inliningContext.callSiteInfo.lineNumber
|
inliningContext.callSiteInfo.lineNumber
|
||||||
),
|
)
|
||||||
null
|
|
||||||
).doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, mapOf())
|
).doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, mapOf())
|
||||||
reifiedTypeParametersUsages?.let(result.reifiedTypeParametersUsages::mergeAll)
|
reifiedTypeParametersUsages?.let(result.reifiedTypeParametersUsages::mergeAll)
|
||||||
deferringVisitor.visitMaxs(-1, -1)
|
deferringVisitor.visitMaxs(-1, -1)
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
node, parameters, info, FieldRemapper(null, null, parameters), sourceCompiler.isCallInsideSameModuleAsCallee,
|
node, parameters, info, FieldRemapper(null, null, parameters), sourceCompiler.isCallInsideSameModuleAsCallee,
|
||||||
"Method inlining " + sourceCompiler.callElementText,
|
"Method inlining " + sourceCompiler.callElementText,
|
||||||
SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, callSite),
|
SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, callSite),
|
||||||
info.callSiteInfo, if (isInlineOnly) InlineOnlySmapSkipper(codegen) else null,
|
info.callSiteInfo, isInlineOnly,
|
||||||
!isInlinedToInlineFunInKotlinRuntime()
|
!isInlinedToInlineFunInKotlinRuntime()
|
||||||
) //with captured
|
) //with captured
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class MethodInliner(
|
|||||||
private val errorPrefix: String,
|
private val errorPrefix: String,
|
||||||
private val sourceMapper: SourceMapCopier,
|
private val sourceMapper: SourceMapCopier,
|
||||||
private val inlineCallSiteInfo: InlineCallSiteInfo,
|
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 shouldPreprocessApiVersionCalls: Boolean = false
|
||||||
) {
|
) {
|
||||||
private val languageVersionSettings = inliningContext.state.languageVersionSettings
|
private val languageVersionSettings = inliningContext.state.languageVersionSettings
|
||||||
@@ -154,9 +154,17 @@ class MethodInliner(
|
|||||||
|
|
||||||
val fakeContinuationName = CoroutineTransformer.findFakeContinuationConstructorClassName(node)
|
val fakeContinuationName = CoroutineTransformer.findFakeContinuationConstructorClassName(node)
|
||||||
val markerShift = calcMarkerShift(parameters, node)
|
val markerShift = calcMarkerShift(parameters, node)
|
||||||
|
var currentLineNumber = if (overrideLineNumber) sourceMapper.callSite!!.line else -1
|
||||||
val lambdaInliner = object : InlineAdapter(remappingMethodAdapter, parameters.argsSizeOnStack, sourceMapper) {
|
val lambdaInliner = object : InlineAdapter(remappingMethodAdapter, parameters.argsSizeOnStack, sourceMapper) {
|
||||||
private var transformationInfo: TransformationInfo? = null
|
private var transformationInfo: TransformationInfo? = null
|
||||||
|
|
||||||
|
override fun visitLineNumber(line: Int, start: Label) {
|
||||||
|
if (!overrideLineNumber) {
|
||||||
|
currentLineNumber = line
|
||||||
|
}
|
||||||
|
super.visitLineNumber(line, start)
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleAnonymousObjectRegeneration() {
|
private fun handleAnonymousObjectRegeneration() {
|
||||||
transformationInfo = iterator.next()
|
transformationInfo = iterator.next()
|
||||||
|
|
||||||
@@ -250,10 +258,29 @@ class MethodInliner(
|
|||||||
store(valueParamShift, type)
|
store(valueParamShift, type)
|
||||||
}
|
}
|
||||||
if (expectedParameters.isEmpty()) {
|
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)
|
addInlineMarker(this, true)
|
||||||
val lambdaParameters = info.addAllParameters(nodeRemapper)
|
val lambdaParameters = info.addAllParameters(nodeRemapper)
|
||||||
|
|
||||||
@@ -270,7 +297,7 @@ class MethodInliner(
|
|||||||
newCapturedRemapper,
|
newCapturedRemapper,
|
||||||
if (info is DefaultLambda) isSameModule else true /*cause all nested objects in same module as lambda*/,
|
if (info is DefaultLambda) isSameModule else true /*cause all nested objects in same module as lambda*/,
|
||||||
"Lambda inlining " + info.lambdaClassType.internalName,
|
"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)
|
val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift)
|
||||||
@@ -284,7 +311,12 @@ class MethodInliner(
|
|||||||
StackValue.coerce(info.invokeMethod.returnType, info.invokeMethodReturnType, OBJECT_TYPE, nullableAnyType, this)
|
StackValue.coerce(info.invokeMethod.returnType, info.invokeMethodReturnType, OBJECT_TYPE, nullableAnyType, this)
|
||||||
setLambdaInlining(false)
|
setLambdaInlining(false)
|
||||||
addInlineMarker(this, 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
|
} else if (isAnonymousConstructorCall(owner, name)) { //TODO add method
|
||||||
//TODO add proper message
|
//TODO add proper message
|
||||||
val newInfo = transformationInfo as? AnonymousObjectTransformationInfo ?: throw AssertionError(
|
val newInfo = transformationInfo as? AnonymousObjectTransformationInfo ?: throw AssertionError(
|
||||||
@@ -371,7 +403,7 @@ class MethodInliner(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val transformationVisitor = object : InlineMethodInstructionAdapter(transformedNode) {
|
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
|
private val isInliningLambda = nodeRemapper.isInsideInliningLambda
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ class SourceMapper(val sourceInfo: SourceInfo?) {
|
|||||||
companion object {
|
companion object {
|
||||||
const val FAKE_FILE_NAME = "fake.kt"
|
const val FAKE_FILE_NAME = "fake.kt"
|
||||||
const val FAKE_PATH = "kotlin/jvm/internal/FakeKt"
|
const val FAKE_PATH = "kotlin/jvm/internal/FakeKt"
|
||||||
|
const val LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import com.intellij.openapi.vfs.VirtualFile
|
|||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.codegen.ASSERTIONS_DISABLED_FIELD_NAME
|
import org.jetbrains.kotlin.codegen.ASSERTIONS_DISABLED_FIELD_NAME
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
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.SamWrapperCodegen.SAM_WRAPPER_SUFFIX
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
|
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
|
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) {
|
fun MethodNode.preprocessSuspendMarkers(forInline: Boolean, keepFakeContinuation: Boolean = true) {
|
||||||
if (instructions.first == null) return
|
if (instructions.first == null) return
|
||||||
if (!keepFakeContinuation) {
|
if (!keepFakeContinuation) {
|
||||||
|
|||||||
Reference in New Issue
Block a user