[K/N][codegen] Added debug info to virtual functions trampolines

#KT-61131 Fixed
This commit is contained in:
Igor Chevdar
2023-08-18 15:58:29 +03:00
committed by Space Team
parent 10df37ba8e
commit c1874d0184
6 changed files with 80 additions and 61 deletions
@@ -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) }
}
}
}
@@ -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) "<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()
@@ -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<IrFunction, DIScopeOpaqueRef?>? = 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(), "<inlined-out:$name>", startLine, subroutineType, nodebug)
}
diFunctionScope(file(), "<inlined-out:$name>", 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) "<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"}
+1 -1
View File
@@ -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.[..]$<bridge-UNN>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: [..]
@@ -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.[..]$<bridge-BNN>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 [..]
+3 -3
View File
@@ -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.[..]$<bridge-BNN>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.[..]$<bridge-BNN>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.[..]$<bridge-BNN>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