[K/N][codegen] Added debug info to virtual functions trampolines
#KT-61131 Fixed
This commit is contained in:
+24
-6
@@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+34
@@ -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()
|
||||
|
||||
|
||||
+17
-50
@@ -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
@@ -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: [..]
|
||||
|
||||
+1
-1
@@ -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 [..]
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user