diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 4249e795ce8..eb1ca844b95 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.ThreadState.Native import org.jetbrains.kotlin.backend.konan.llvm.ThreadState.Runnable import org.jetbrains.kotlin.backend.konan.llvm.objc.* import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.konan.ForeignExceptionMode @@ -334,12 +335,29 @@ private fun CodeGenerator.getVirtualFunctionTrampolineImpl(irFunction: IrSimpleF ) if (isExternal(irFunction)) llvm.externalFunction(proto) - else generateFunction(this, proto, needSafePoint = false) { - val args = proto.signature.parameterTypes.indices.map { param(it) } - val receiver = param(0) - val callee = with(VirtualTablesLookup) { getVirtualImpl(receiver, irFunction) } - val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true) - ret(result) + else { + val offset = irFunction.startOffset.takeIf { it != UNDEFINED_OFFSET } + ?: irFunction.parentAsClass.startOffset.takeIf { it != UNDEFINED_OFFSET } + val file = irFunction.fileOrNull.takeIf { + offset != null && context.shouldContainLocationDebugInfo() + } + val diFunctionScope = file?.let { + with(generationState.debugInfo) { + irFunction.diFunctionScope(it, proto.name, it.fileEntry.line(offset!!), false) + } + } + @Suppress("UNCHECKED_CAST") val location = diFunctionScope?.let { + LocationInfo(it as DIScopeOpaqueRef, file.fileEntry.line(offset!!), file.fileEntry.column(offset)) + } + generateFunction(this, proto, needSafePoint = false, startLocation = location, endLocation = location) { + val args = proto.signature.parameterTypes.indices.map { param(it) } + val receiver = param(0) + val callee = with(VirtualTablesLookup) { getVirtualImpl(receiver, irFunction) } + val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true) + ret(result) + }.also { llvmFunction -> + diFunctionScope?.let { llvmFunction.addDebugInfoSubprogram(it) } + } } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt index 99d8655c002..79fa5facaf1 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt @@ -12,6 +12,7 @@ import llvm.* import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.ir.IrFileEntry import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull @@ -171,6 +172,39 @@ internal class DebugInfo(override val generationState: NativeGenerationState) : DICreateSubroutineType(builder, allocArrayOf(types.map { it.diType(llvmTargetData) }), types.size)!! } + fun IrFile.diFileScope() = files.getOrPut(this.fileEntry.name) { + val path = this.fileEntry.name.toFileAndFolder(context.config) + DICreateFile(builder, path.file, path.folder)!! + } + + fun IrFunction.diFunctionScope( + file: IrFile, + linkageName: String, + startLine: Int, + nodebug: Boolean, + ) = diFunctionScope(file, name.asString(), linkageName, startLine, subroutineType(llvmTargetData), nodebug) + + fun diFunctionScope( + file: IrFile, + name: String, + linkageName: String, + startLine: Int, + subroutineType: DISubroutineTypeRef, + nodebug: Boolean, + ) = DICreateFunction( + builder = builder, + scope = compilationUnit, + name = (if (nodebug) "" else "") + name, + linkageName = linkageName, + file = file.diFileScope(), + lineNo = startLine, + type = subroutineType, + //TODO: need more investigations. + isLocal = 0, + isDefinition = 1, + scopeLine = 0 + )!! + private fun dwarfPointerType(type: DITypeOpaqueRef): DITypeOpaqueRef = DICreatePointerType(builder, type)!!.reinterpret() diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 170a71374e9..92a0ad6e01c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -39,8 +39,6 @@ import org.jetbrains.kotlin.konan.target.Family import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.uniqueName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.descriptorUtil.classId -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe internal enum class FieldStorageKind { GLOBAL, // In the old memory model these are only accessible from the "main" thread. @@ -1397,7 +1395,7 @@ internal class CodeGeneratorVisitor( if (function == null || !element.needDebugInfo(context) || currentCodeContext.scope() == null) return null val locationInfo = element.startLocation ?: return null val location = codegen.generateLocationInfo(locationInfo) - val file = (currentCodeContext.fileScope() as FileScope).file.file() + val file = (currentCodeContext.fileScope() as FileScope).file.diFileScope() return when (element) { is IrVariable -> if (shouldGenerateDebugInfo(element)) debugInfoLocalVariableLocation( builder = debugInfo.builder, @@ -2083,8 +2081,8 @@ internal class CodeGeneratorVisitor( private val scope by lazy { if (!context.shouldContainLocationDebugInfo() || returnableBlock.startOffset == UNDEFINED_OFFSET) return@lazy null - val lexicalBlockFile = DICreateLexicalBlockFile(debugInfo.builder, functionScope()!!.scope(), super.file.file()) - DICreateLexicalBlock(debugInfo.builder, lexicalBlockFile, super.file.file(), returnableBlock.startLine(), returnableBlock.startColumn())!! + val lexicalBlockFile = DICreateLexicalBlockFile(debugInfo.builder, functionScope()!!.scope(), super.file.diFileScope()) + DICreateLexicalBlock(debugInfo.builder, lexicalBlockFile, super.file.diFileScope(), returnableBlock.startLine(), returnableBlock.startColumn())!! } override fun scope() = scope @@ -2102,7 +2100,7 @@ internal class CodeGeneratorVisitor( private val scope by lazy { if (!context.shouldContainLocationDebugInfo()) return@lazy null - file.file() as DIScopeOpaqueRef? + file.diFileScope() as DIScopeOpaqueRef? } override fun scope() = scope @@ -2244,7 +2242,7 @@ internal class CodeGeneratorVisitor( refBuilder = builder, refScope = scope.scope as DIScopeOpaqueRef, name = expression.computeSymbolName(), - file = irFile.file(), + file = irFile.diFileScope(), lineNum = expression.startLine(), sizeInBits = sizeInBits, alignInBits = alignInBits, @@ -2255,16 +2253,7 @@ internal class CodeGeneratorVisitor( } } - - //-------------------------------------------------------------------------// - private fun IrFile.file(): DIFileRef { - return debugInfo.files.getOrPut(this.fileEntry.name) { - val path = this.fileEntry.name.toFileAndFolder(context.config) - DICreateFile(debugInfo.builder, path.file, path.folder)!! - } - } - - //-------------------------------------------------------------------------// + private fun IrFile.diFileScope() = with(debugInfo) { diFileScope() } // Saved calculated IrFunction scope which is used several time for getting locations and generating debug info. private var irFunctionSavedScope: Pair? = null @@ -2296,20 +2285,14 @@ internal class CodeGeneratorVisitor( val nodebug = f is IrConstructor && f.parentAsClass.isSubclassOf(context.irBuiltIns.throwableClass.owner) if (functionLlvmValue != null) { subprograms.getOrPut(functionLlvmValue) { - memScoped { - val subroutineType = subroutineType(codegen.llvmTargetData) - diFunctionScope(name.asString(), functionLlvmValue.name!!, startLine, subroutineType, nodebug).also { - if (!this@scope.isInline) - functionLlvmValue.addDebugInfoSubprogram(it) - } + diFunctionScope(file(), functionLlvmValue.name!!, startLine, nodebug).also { + if (!this@scope.isInline) + functionLlvmValue.addDebugInfoSubprogram(it) } } as DIScopeOpaqueRef } else { inlinedSubprograms.getOrPut(this@scope) { - memScoped { - val subroutineType = subroutineType(codegen.llvmTargetData) - diFunctionScope(name.asString(), "", startLine, subroutineType, nodebug) - } + diFunctionScope(file(), "", startLine, nodebug) } as DIScopeOpaqueRef } } @@ -2317,30 +2300,14 @@ internal class CodeGeneratorVisitor( } @Suppress("UNCHECKED_CAST") - private fun LlvmCallable.scope(startLine:Int, subroutineType: DISubroutineTypeRef, nodebug: Boolean): DIScopeOpaqueRef? { - return debugInfo.subprograms.getOrPut(this) { - diFunctionScope(name!!, name!!, startLine, subroutineType, nodebug).also { - this@scope.addDebugInfoSubprogram(it) + private fun LlvmCallable.scope(startLine: Int, subroutineType: DISubroutineTypeRef, nodebug: Boolean) = + with(debugInfo) { + subprograms.getOrPut(this@scope) { + diFunctionScope(file(), name!!, name!!, startLine, subroutineType, nodebug).also { + this@scope.addDebugInfoSubprogram(it) + } + } as DIScopeOpaqueRef } - } as DIScopeOpaqueRef - } - - @Suppress("UNCHECKED_CAST") - private fun diFunctionScope(name: String, linkageName: String, startLine: Int, subroutineType: DISubroutineTypeRef, nodebug: Boolean) = DICreateFunction( - builder = debugInfo.builder, - scope = debugInfo.compilationUnit, - name = (if (nodebug) "" else "") + name, - linkageName = linkageName, - file = file().file(), - lineNo = startLine, - type = subroutineType, - //TODO: need more investigations. - isLocal = 0, - isDefinition = 1, - scopeLine = 0)!! - - //-------------------------------------------------------------------------// - private fun IrFunction.returnsUnit() = returnType.isUnit().also { require(!isSuspend) { "Suspend functions should be lowered out at this point"} diff --git a/native/native.tests/testData/lldb/kt42208.txt b/native/native.tests/testData/lldb/kt42208.txt index a97911b3613..c2817783da0 100644 --- a/native/native.tests/testData/lldb/kt42208.txt +++ b/native/native.tests/testData/lldb/kt42208.txt @@ -6,7 +6,7 @@ frame #1: [..]`kfun:[..]main$lambda$0[..] at kt42208-2.kt:10:18 frame #2: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0[..]invoke[..](_this=[..])[..] at kt42208-1.kt:7:60 frame #3: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0.[..]$invoke(_this=[..]){}kotlin.Nothing[..] at kt42208-1.kt:7:60 - frame #4: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline [..] + frame #4: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline at [K][Suspend]Functions:1:1 frame #5: [..]`kfun:#main(){} at kt42208-1.kt:5:5 frame #6: [..]`Konan_start(args=[..]) at [..] frame #7: [..] diff --git a/native/native.tests/testData/lldb/kt42208WithPassingLambdaToAnotherFunction.txt b/native/native.tests/testData/lldb/kt42208WithPassingLambdaToAnotherFunction.txt index 649a1a6e4af..b8231357e7d 100644 --- a/native/native.tests/testData/lldb/kt42208WithPassingLambdaToAnotherFunction.txt +++ b/native/native.tests/testData/lldb/kt42208WithPassingLambdaToAnotherFunction.txt @@ -5,7 +5,7 @@ * frame #0: [..]`kfun:[..]main$lambda$0[..] at kt42208-2.kt:14:5 frame #1: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0.[..]invoke[..](_this=[..])[..] at kt42208-1.kt:9:82 frame #2: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0.[..]$invoke(_this=[..]){}kotlin.Boolean[..] at kt42208-1.kt:9:82 - frame #3: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline [..] + frame #3: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline at [K][Suspend]Functions:1:1 frame #4: [..]`kfun:#bar(v=[..]){} at kt42208-3.kt:18:5 frame #5: [..]`kfun:#main(){} at kt42208-1.kt:7:5 frame #6: [..]`Konan_start(args=[..]) at [..] diff --git a/native/native.tests/testData/lldb/kt42208WithVariable.txt b/native/native.tests/testData/lldb/kt42208WithVariable.txt index 8958e2bbd10..8a3692ae7af 100644 --- a/native/native.tests/testData/lldb/kt42208WithVariable.txt +++ b/native/native.tests/testData/lldb/kt42208WithVariable.txt @@ -5,7 +5,7 @@ * frame #0: [..]`kfun:[..]main$lambda$0[..] at kt42208-2.kt:15:5 frame #1: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0[..]invoke[..](_this=[..])[..] at kt42208-1.kt:10:71 frame #2: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0.[..]$invoke(_this=[..]){}kotlin.Boolean[..] at kt42208-1.kt:10:71 - frame #3: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline [..] + frame #3: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline at [K][Suspend]Functions:1:1 frame #4: [..]`kfun:#main(){} at kt42208-1.kt:6:5 frame #5: [..]`Konan_start(args=[..]) at [..] frame #6: [..] @@ -15,7 +15,7 @@ * frame #0: [..]`kfun:[..]main$lambda$0[..] at kt42208-2.kt:15:5 frame #1: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0[..]invoke[..](_this=[..])[..] at kt42208-1.kt:10:71 frame #2: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0.[..]$invoke(_this=[..]){}kotlin.Boolean[..] at kt42208-1.kt:10:71 - frame #3: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline [..] + frame #3: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline at [K][Suspend]Functions:1:1 frame #4: [..]`kfun:#main(){} at kt42208-1.kt:7:5 frame #5: [..]`Konan_start(args=[..]) at [..] > c @@ -24,7 +24,7 @@ * frame #0: [..]`kfun:[..]main$lambda$0[..] at kt42208-2.kt:15:5 frame #1: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0[..]invoke[..](_this=[..])[..] at kt42208-1.kt:10:71 frame #2: [..]`kfun:$main$lambda$0$FUNCTION_REFERENCE$0.[..]$invoke(_this=[..]){}kotlin.Boolean[..] at kt42208-1.kt:10:71 - frame #3: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline [..] + frame #3: [..]`kfun:kotlin.Function0#invoke(){}1:0-trampoline at [K][Suspend]Functions:1:1 frame #4: [..]`kfun:#main(){} at kt42208-1.kt:8:5 frame #5: [..]`Konan_start(args=[..]) at [..] > q