diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 829791be970..88648f8b91a 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -155,6 +155,11 @@ private inline fun generateFunctionBody( functionGenerationContext.resetDebugLocation() } +internal fun FunctionGenerationContext.initBridgeDebugInfo() { + val location = setupBridgeDebugInfo(context, function) ?: return + debugLocation(location, location) +} + /** * There're cases when we don't need end position or it is meaningless. */ diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt index 6d554c044f5..43b74579986 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.allocArrayOf import kotlinx.cinterop.memScoped +import kotlinx.cinterop.reinterpret import llvm.* import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.ir.SourceManager.FileEntry @@ -81,6 +82,10 @@ internal class DebugInfo internal constructor(override val context: Context):Con val otherLlvmType = LLVMPointerType(LLVMInt64Type(), 0)!! val otherTypeSize = LLVMSizeOfTypeInBits(llvmTargetData, otherLlvmType) val otherTypeAlignment = LLVMPreferredAlignmentOfType(llvmTargetData, otherLlvmType) + + val compilerGeneratedFile by lazy { + DICreateFile(builder, "", "")!! + } } /** @@ -250,3 +255,29 @@ internal fun subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef, @Suppress("UNCHECKED_CAST") private fun dwarfPointerType(context: Context, type: DITypeOpaqueRef) = DICreatePointerType(context.debugInfo.builder, type) as DITypeOpaqueRef + +internal fun setupBridgeDebugInfo(context: Context, function: LLVMValueRef): LocationInfo? { + if (!context.shouldContainLocationDebugInfo()) { + return null + } + + val file = context.debugInfo.compilerGeneratedFile + + // TODO: can we share the scope among all bridges? + val scope: DIScopeOpaqueRef = DICreateFunction( + builder = context.debugInfo.builder, + scope = file.reinterpret(), + name = function.name, + linkageName = function.name, + file = file, + lineNo = 0, + type = subroutineType(context, context.llvm.runtime.targetData, emptyList()), // TODO: use proper type. + isLocal = 0, + isDefinition = 1, + scopeLine = 0 + )!!.also { + DIFunctionAddSubprogram(function, it) + }.reinterpret() + + return LocationInfo(scope, 1, 0) +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index 682e2db5fb1..e16d281ad0d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -535,7 +535,7 @@ private inline fun ObjCExportCodeGenerator.generateObjCImpBy( genBody() } - LLVMSetLinkage(result, LLVMLinkage.LLVMPrivateLinkage) + LLVMSetLinkage(result, LLVMLinkage.LLVMInternalLinkage) return result } @@ -555,7 +555,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp( ) = if (target == null) { generateAbstractObjCImp(methodBridge) } else { - generateObjCImp(methodBridge) { args, resultLifetime, exceptionHandler -> + generateObjCImp(methodBridge, isDirect = !isVirtual) { args, resultLifetime, exceptionHandler -> val llvmTarget = if (!isVirtual) { codegen.llvmFunction(target) } else { @@ -568,12 +568,19 @@ private fun ObjCExportCodeGenerator.generateObjCImp( private fun ObjCExportCodeGenerator.generateObjCImp( methodBridge: MethodBridge, + isDirect: Boolean, callKotlin: FunctionGenerationContext.( args: List, resultLifetime: Lifetime, exceptionHandler: ExceptionHandler ) -> LLVMValueRef? ): LLVMValueRef = generateObjCImpBy(methodBridge) { + if (isDirect) { + // Consider this call inlinable. If it is inlined into a bridge with no debug information, + // lldb will not decode the inlined frame even if the callee has debug information. + initBridgeDebugInfo() + // TODO: consider adding debug info to other bridges. + } val returnType = methodBridge.returnBridge @@ -674,7 +681,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp( private fun ObjCExportCodeGenerator.generateObjCImpForArrayConstructor( target: IrConstructor, methodBridge: MethodBridge -): LLVMValueRef = generateObjCImp(methodBridge) { args, resultLifetime, exceptionHandler -> +): LLVMValueRef = generateObjCImp(methodBridge, isDirect = true) { args, resultLifetime, exceptionHandler -> val arrayInstance = callFromBridge( context.llvm.allocArrayFunction, listOf(target.constructedClass.llvmTypeInfoPtr, args.first()),