JVM: keep call site markers when inlining lambdas into objects
A follow-up for KT-35006:
fun f() = foo {
bar()
}
inline fun foo(crossinline x: () -> Unit) = { x() }()
inline fun bar() = TODO()
does not provide the option to navigate to bar's call site at all.
This commit is contained in:
+1
-1
@@ -290,7 +290,7 @@ class AnonymousObjectTransformer(
|
|||||||
remapper,
|
remapper,
|
||||||
isSameModule,
|
isSameModule,
|
||||||
"Transformer for " + transformationInfo.oldClassName,
|
"Transformer for " + transformationInfo.oldClassName,
|
||||||
SourceMapCopier(sourceMapper, sourceMap, keepCallSites = inliningContext.isInliningLambda),
|
SourceMapCopier(sourceMapper, sourceMap),
|
||||||
InlineCallSiteInfo(
|
InlineCallSiteInfo(
|
||||||
transformationInfo.oldClassName,
|
transformationInfo.oldClassName,
|
||||||
sourceNode.name,
|
sourceNode.name,
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
var activeLambda: LambdaInfo? = null
|
var activeLambda: LambdaInfo? = null
|
||||||
protected set
|
protected set
|
||||||
|
|
||||||
private val defaultSourceMapper = sourceCompiler.lazySourceMapper
|
private val sourceMapper = sourceCompiler.lazySourceMapper
|
||||||
|
|
||||||
protected var delayedHiddenWriting: Function0<Unit>? = null
|
protected var delayedHiddenWriting: Function0<Unit>? = null
|
||||||
|
|
||||||
@@ -208,7 +208,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
|
|
||||||
protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, inlineDefaultLambda: Boolean, isCallOfFunctionInCorrespondingDefaultDispatch: Boolean): InlineResult {
|
protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, inlineDefaultLambda: Boolean, isCallOfFunctionInCorrespondingDefaultDispatch: Boolean): InlineResult {
|
||||||
assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" }
|
assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" }
|
||||||
if (!isCallOfFunctionInCorrespondingDefaultDispatch) defaultSourceMapper.callSiteMarker = codegen.lastLineNumber
|
|
||||||
val node = nodeAndSmap.node
|
val node = nodeAndSmap.node
|
||||||
if (inlineDefaultLambda) {
|
if (inlineDefaultLambda) {
|
||||||
for (lambda in extractDefaultLambdas(node)) {
|
for (lambda in extractDefaultLambdas(node)) {
|
||||||
@@ -230,11 +229,13 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
sourceCompiler, sourceCompiler.inlineCallSiteInfo, reifiedTypeInliner, typeParameterMappings
|
sourceCompiler, sourceCompiler.inlineCallSiteInfo, reifiedTypeInliner, typeParameterMappings
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val sourceInfo = sourceMapper.sourceInfo!!
|
||||||
|
val callSite = SourcePosition(codegen.lastLineNumber, sourceInfo.source, sourceInfo.pathOrCleanFQN)
|
||||||
val inliner = MethodInliner(
|
val inliner = MethodInliner(
|
||||||
node, parameters, info, FieldRemapper(null, null, parameters), isSameModule,
|
node, parameters, info, FieldRemapper(null, null, parameters), isSameModule,
|
||||||
"Method inlining " + sourceCompiler.callElementText,
|
"Method inlining " + sourceCompiler.callElementText,
|
||||||
SourceMapCopier(defaultSourceMapper, nodeAndSmap.classSMAP), info.callSiteInfo,
|
SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, callSite.takeIf { !isCallOfFunctionInCorrespondingDefaultDispatch }),
|
||||||
if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null,
|
info.callSiteInfo, if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null,
|
||||||
!isInlinedToInlineFunInKotlinRuntime()
|
!isInlinedToInlineFunInKotlinRuntime()
|
||||||
) //with captured
|
) //with captured
|
||||||
|
|
||||||
@@ -269,9 +270,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
if (shouldSpillStack) {
|
if (shouldSpillStack) {
|
||||||
addInlineMarker(codegen.v, false)
|
addInlineMarker(codegen.v, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCallOfFunctionInCorrespondingDefaultDispatch) defaultSourceMapper.callSiteMarker = null
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ class InlineCodegenForDefaultBody(
|
|||||||
val nodeAndSmap = InlineCodegen.createInlineMethodNode(
|
val nodeAndSmap = InlineCodegen.createInlineMethodNode(
|
||||||
function, methodOwner, jvmSignature, callDefault, null, codegen.typeSystem, state, sourceCompilerForInline
|
function, methodOwner, jvmSignature, callDefault, null, codegen.typeSystem, state, sourceCompilerForInline
|
||||||
)
|
)
|
||||||
val childSourceMapper = SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, keepCallSites = true)
|
val childSourceMapper = SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP)
|
||||||
|
|
||||||
val node = nodeAndSmap.node
|
val node = nodeAndSmap.node
|
||||||
val transformedMethod = MethodNode(
|
val transformedMethod = MethodNode(
|
||||||
|
|||||||
@@ -289,16 +289,13 @@ class MethodInliner(
|
|||||||
|
|
||||||
setLambdaInlining(true)
|
setLambdaInlining(true)
|
||||||
|
|
||||||
// TODO we cannot keep call site markers when inlining lambdas into objects because AnonymousObjectTransformer
|
val callSite = sourceMapper.callSite.takeIf { info is DefaultLambda }
|
||||||
// uses the original's source info, thus KotlinDebug would point to the file with the inline function
|
|
||||||
// instead of the one with the call.
|
|
||||||
val sameFile = info !is DefaultLambda && (!inliningContext.classRegeneration || inliningContext.isInliningLambda)
|
|
||||||
val inliner = MethodInliner(
|
val inliner = MethodInliner(
|
||||||
info.node.node, lambdaParameters, inliningContext.subInlineLambda(info),
|
info.node.node, lambdaParameters, inliningContext.subInlineLambda(info),
|
||||||
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, sameFile), inlineCallSiteInfo, null
|
SourceMapCopier(sourceMapper.parent, info.node.classSMAP, callSite), inlineCallSiteInfo, null
|
||||||
)
|
)
|
||||||
|
|
||||||
val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift)
|
val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ object SMAPBuilder {
|
|||||||
lineMappings.joinToString("") { it.toSMAP(id, mapToFirstLine) }
|
lineMappings.joinToString("") { it.toSMAP(id, mapToFirstLine) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class SourceMapCopier(val parent: SourceMapper, private val smap: SMAP, private val keepCallSites: Boolean = false) {
|
class SourceMapCopier(val parent: SourceMapper, private val smap: SMAP, val callSite: SourcePosition? = null) {
|
||||||
private val visitedLines = TIntIntHashMap()
|
private val visitedLines = TIntIntHashMap()
|
||||||
private var lastVisitedRange: RangeMapping? = null
|
private var lastVisitedRange: RangeMapping? = null
|
||||||
|
|
||||||
@@ -79,10 +79,7 @@ class SourceMapCopier(val parent: SourceMapper, private val smap: SMAP, private
|
|||||||
if (inlineSource.line < 0) {
|
if (inlineSource.line < 0) {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
val inlineCallSite = if (keepCallSites) range.callSite else parent.callSiteMarker?.let {
|
val newLineNumber = parent.mapLineNumber(inlineSource, callSite ?: range.callSite)
|
||||||
SourcePosition(it, parent.sourceInfo!!.source, parent.sourceInfo.pathOrCleanFQN)
|
|
||||||
}
|
|
||||||
val newLineNumber = parent.mapLineNumber(inlineSource, inlineCallSite)
|
|
||||||
visitedLines.put(lineNumber, newLineNumber)
|
visitedLines.put(lineNumber, newLineNumber)
|
||||||
lastVisitedRange = range
|
lastVisitedRange = range
|
||||||
return newLineNumber
|
return newLineNumber
|
||||||
@@ -95,14 +92,12 @@ class SourceMapper(val sourceInfo: SourceInfo?) {
|
|||||||
private var maxUsedValue: Int = sourceInfo?.linesInFile ?: 0
|
private var maxUsedValue: Int = sourceInfo?.linesInFile ?: 0
|
||||||
private var fileMappings: LinkedHashMap<Pair<String, String>, FileMapping> = linkedMapOf()
|
private var fileMappings: LinkedHashMap<Pair<String, String>, FileMapping> = linkedMapOf()
|
||||||
|
|
||||||
var callSiteMarker: Int? = null
|
|
||||||
|
|
||||||
val resultMappings: List<FileMapping>
|
val resultMappings: List<FileMapping>
|
||||||
get() = fileMappings.values.toList()
|
get() = fileMappings.values.toList()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
sourceInfo?.let {
|
sourceInfo?.let {
|
||||||
// Explicitly map the file to itself -- we'll probably need a lot of lines from it, so this will produce less ranges.
|
// Explicitly map the file to itself -- we'll probably need a lot of lines from it, so this will produce fewer ranges.
|
||||||
getOrRegisterNewSource(it.source, it.pathOrCleanFQN).mapNewInterval(1, 1, it.linesInFile)
|
getOrRegisterNewSource(it.source, it.pathOrCleanFQN).mapNewInterval(1, 1, it.linesInFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -281,7 +281,7 @@ abstract class ClassCodegen protected constructor(
|
|||||||
method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE
|
method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE
|
||||||
)
|
)
|
||||||
val mv = with(node) { visitor.newMethod(method.OtherOrigin, access, name, desc, signature, exceptions.toTypedArray()) }
|
val mv = with(node) { visitor.newMethod(method.OtherOrigin, access, name, desc, signature, exceptions.toTypedArray()) }
|
||||||
val smapCopier = SourceMapCopier(classSMAP, smap, keepCallSites = true)
|
val smapCopier = SourceMapCopier(classSMAP, smap)
|
||||||
val smapCopyingVisitor = object : MethodVisitor(Opcodes.API_VERSION, mv) {
|
val smapCopyingVisitor = object : MethodVisitor(Opcodes.API_VERSION, mv) {
|
||||||
override fun visitLineNumber(line: Int, start: Label) =
|
override fun visitLineNumber(line: Int, start: Label) =
|
||||||
super.visitLineNumber(smapCopier.mapLineNumber(line), start)
|
super.visitLineNumber(smapCopier.mapLineNumber(line), start)
|
||||||
|
|||||||
+8
@@ -73,4 +73,12 @@ _2Kt
|
|||||||
10#2:20
|
10#2:20
|
||||||
15#2:22
|
15#2:22
|
||||||
7#3:21
|
7#3:21
|
||||||
|
*E
|
||||||
|
*S KotlinDebug
|
||||||
|
*F
|
||||||
|
+ 1 1.kt
|
||||||
|
test/_1Kt$annotatedWith2$1
|
||||||
|
*L
|
||||||
|
6#1:19
|
||||||
|
6#1:22
|
||||||
*E
|
*E
|
||||||
@@ -94,3 +94,11 @@ _2Kt
|
|||||||
9#2:24
|
9#2:24
|
||||||
9#3,2:22
|
9#3,2:22
|
||||||
*E
|
*E
|
||||||
|
*S KotlinDebug
|
||||||
|
*F
|
||||||
|
+ 1 1.kt
|
||||||
|
test/_1Kt$test$1
|
||||||
|
*L
|
||||||
|
14#1,2:20
|
||||||
|
14#1:24
|
||||||
|
*E
|
||||||
|
|||||||
Reference in New Issue
Block a user