From fea734ec8305620cff09ac7736cb2ce738759846 Mon Sep 17 00:00:00 2001 From: Vasily Levchenko Date: Wed, 25 Oct 2017 18:26:09 +0300 Subject: [PATCH] [codegen][debug] generation debug info for vals. --- .../jetbrains/kotlin/backend/konan/Context.kt | 2 +- .../backend/konan/llvm/CodeGenerator.kt | 11 +- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 107 ++++++++++++------ .../backend/konan/llvm/VariableManager.kt | 80 ++++++++++--- llvmDebugInfoC/src/main/cpp/DebugInfoC.cpp | 10 ++ llvmDebugInfoC/src/main/include/DebugInfoC.h | 1 + runtime/src/main/cpp/Memory.cpp | 10 +- runtime/src/main/cpp/Memory.h | 4 +- 8 files changed, 163 insertions(+), 62 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 69de01f9123..40324439529 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -365,6 +365,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { } } - lateinit var debugInfo:DebugInfo + lateinit var debugInfo: DebugInfo } 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 a0f81b99a9a..8541cf9d12d 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 @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.ir.declarations.IrValueParameter internal class CodeGenerator(override val context: Context) : ContextUtils { @@ -478,6 +479,12 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, private fun position() = basicBlockToLastLocation[currentBlock] + internal fun mapParameterForDebug(index: Int, value: LLVMValueRef) { + appendingTo(localsInitBb) { + LLVMBuildStore(builder, value, vars.addressOf(index)) + } + } + internal fun prologue() { assert(returns.isEmpty()) if (isObjectType(returnType!!)) { @@ -505,7 +512,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, Int32(slotCount * codegen.runtime.pointerSize).llvm, Int32(codegen.runtime.pointerAlignment).llvm, Int1(0).llvm)) - call(context.llvm.enterFrameFunction, listOf(slots, Int32(slotCount).llvm)) + call(context.llvm.enterFrameFunction, listOf(slots, Int32(vars.skip).llvm, Int32(slotCount).llvm)) } addPhiIncoming(slotsPhi!!, prologueBb to slots) memScoped { @@ -669,7 +676,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, private fun releaseVars() { if (needSlots) { call(context.llvm.leaveFrameFunction, - listOf(slotsPhi!!, Int32(slotCount).llvm)) + listOf(slotsPhi!!, Int32(vars.skip).llvm, Int32(slotCount).llvm)) } } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 45de3a865e7..50a78d5a4ff 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -31,8 +31,10 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid @@ -463,17 +465,30 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map): InnerScopeImpl() { + private open inner class ParameterScope( + function: IrFunction?, + private val functionGenerationContext: FunctionGenerationContext): InnerScopeImpl() { - // Note: it is possible to generate access to a parameter without any variables, - // however variables are named and thus the resulting bitcode can be more readable. + val parameters = bindParameters(function?.descriptor) init { - parameters.map { (descriptor, value) -> - functionGenerationContext.vars.createImmutable(descriptor, value) - } + if (function != null) { + parameters.forEach{ + val descriptor = it.key + val ir = when { + descriptor is ValueParameterDescriptor -> function.getIrValueParameter(descriptor) + descriptor is ReceiverParameterDescriptor && function.extensionReceiverParameter?.descriptor == descriptor -> function.extensionReceiverParameter!! + descriptor is ReceiverParameterDescriptor && function.dispatchReceiverParameter?.descriptor == descriptor-> function.dispatchReceiverParameter!! + function.descriptor is ClassConstructorDescriptor && (function.descriptor as ClassConstructorDescriptor).constructedClass.thisAsReceiverParameter == descriptor-> IrValueParameterImpl(function.startOffset, function.startOffset, object: IrDeclarationOriginImpl("THIS"){}, descriptor) + else -> TODO() + } + val local = functionGenerationContext.vars.createParameter(descriptor, + it.value, debugInfoIfNeeded(function, ir)) + functionGenerationContext.mapParameterForDebug(local, it.value) + + } + } } override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef { @@ -489,10 +504,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map { + private fun bindParameters(descriptor: FunctionDescriptor?): Map { if (descriptor == null) return emptyMap() val parameterDescriptors = descriptor.allParameters return parameterDescriptors.mapIndexed { i, parameterDescriptor -> @@ -549,22 +566,27 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map body.statements.forEach { generateStatement(it) } - is IrExpressionBody -> generateStatement(body.expression) - is IrSyntheticBody -> throw AssertionError("Synthetic body ${body.kind} has not been lowered") - else -> TODO(ir2string(body)) + val parameterScope = ParameterScope(declaration, functionGenerationContext) + using(parameterScope) { + using(VariableScope()) { + when (body) { + is IrBlockBody -> body.statements.forEach { generateStatement(it) } + is IrExpressionBody -> generateStatement(body.expression) + is IrSyntheticBody -> throw AssertionError("Synthetic body ${body.kind} has not been lowered") + else -> TODO(ir2string(body)) + } } } } @@ -1070,25 +1092,41 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map debugInfoLocalVariableLocation( + builder = context.debugInfo.builder, functionScope = functionScope, - diType = variableDescriptor.type.diType(context, functionGenerationContext.llvmTargetData), - name = variableDescriptor.name, + diType = element.descriptor.type.diType(context, codegen.llvmTargetData), + name = element.descriptor.name, file = file, line = line, location = location) - } else null - currentCodeContext.genDeclareVariable(variableDescriptor, result, variableLocation) + is IrValueParameter -> debugInfoParameterLocation( + builder = context.debugInfo.builder, + functionScope = functionScope, + diType = element.descriptor.type.diType(context, codegen.llvmTargetData), + name = element.descriptor.name, + argNo = (element.descriptor as? ValueParameterDescriptor)?.index ?: 0, + file = file, + line = line, + location = location) + else -> throw Error("Unsupported element type: ${ir2string(element)}") + } + } + + private fun generateVariable(variable: IrVariable) { + context.log{"generateVariable : ${ir2string(variable)}"} + val value = variable.initializer?.let { evaluateExpression(it) } + currentCodeContext.genDeclareVariable( + variable.descriptor, value, debugInfoIfNeeded( + (currentCodeContext.functionScope() as FunctionScope)?.declaration, variable)) } //-------------------------------------------------------------------------// @@ -2414,3 +2452,4 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: MapcreateParameterVariable( + llvm::unwrap(scope), + name, + argNo, + llvm::unwrap(file), + line, + llvm::unwrap(type))); +} + DIExpressionRef DICreateEmptyExpression(DIBuilderRef builder) { return llvm::wrap(llvm::unwrap(builder)->createExpression()); } diff --git a/llvmDebugInfoC/src/main/include/DebugInfoC.h b/llvmDebugInfoC/src/main/include/DebugInfoC.h index 69cbde2415d..bd9086417f9 100644 --- a/llvmDebugInfoC/src/main/include/DebugInfoC.h +++ b/llvmDebugInfoC/src/main/include/DebugInfoC.h @@ -93,6 +93,7 @@ DISubroutineTypeRef DICreateSubroutineType(DIBuilderRef builder, unsigned typesCount); DILocalVariableRef DICreateAutoVariable(DIBuilderRef builder, DIScopeOpaqueRef scope, const char *name, DIFileRef file, unsigned line, DITypeOpaqueRef type); +DILocalVariableRef DICreateParameterVariable(DIBuilderRef builder, DIScopeOpaqueRef scope, const char *name, unsigned argNo, DIFileRef file, unsigned line, DITypeOpaqueRef type); void DIInsertDeclaration(DIBuilderRef builder, LLVMValueRef value, DILocalVariableRef localVariable, DILocationRef location, LLVMBasicBlockRef bb, int64_t *expr, uint64_t exprCount); DIExpressionRef DICreateEmptyExpression(DIBuilderRef builder); void DIFunctionAddSubprogram(LLVMValueRef fn, DISubprogramRef sp); diff --git a/runtime/src/main/cpp/Memory.cpp b/runtime/src/main/cpp/Memory.cpp index 2d163c960a7..25923d944b8 100644 --- a/runtime/src/main/cpp/Memory.cpp +++ b/runtime/src/main/cpp/Memory.cpp @@ -1080,13 +1080,13 @@ void UpdateRef(ObjHeader** location, const ObjHeader* object) { } } -void EnterFrame(ObjHeader** start, int count) { - MEMORY_LOG("EnterFrame %p .. %p\n", start, start + count) +void EnterFrame(ObjHeader** start, int parameters, int count) { + MEMORY_LOG("EnterFrame %p .. %p\n", start, start + count + parameters) } -void LeaveFrame(ObjHeader** start, int count) { - MEMORY_LOG("LeaveFrame %p .. %p\n", start, start + count) - ReleaseRefs(start + kFrameOverlaySlots, count - kFrameOverlaySlots); +void LeaveFrame(ObjHeader** start, int parameters, int count) { + MEMORY_LOG("LeaveFrame %p .. %p\n", start, start + count + parameters) + ReleaseRefs(start + parameters + kFrameOverlaySlots, count - kFrameOverlaySlots - parameters); if (*start != nullptr) { auto arena = initedArena(start); MEMORY_LOG("LeaveFrame: free arena %p\n", arena) diff --git a/runtime/src/main/cpp/Memory.h b/runtime/src/main/cpp/Memory.h index bb1b8420018..60a4e255398 100644 --- a/runtime/src/main/cpp/Memory.h +++ b/runtime/src/main/cpp/Memory.h @@ -362,9 +362,9 @@ void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) RUNTIME_NO // Optimization: release all references in range. void ReleaseRefs(ObjHeader** start, int count) RUNTIME_NOTHROW; // Called on frame enter, if it has object slots. -void EnterFrame(ObjHeader** start, int count) RUNTIME_NOTHROW; +void EnterFrame(ObjHeader** start, int parameters, int count) RUNTIME_NOTHROW; // Called on frame leave, if it has object slots. -void LeaveFrame(ObjHeader** start, int count) RUNTIME_NOTHROW; +void LeaveFrame(ObjHeader** start, int parameters, int count) RUNTIME_NOTHROW; // Tries to use returnSlot's arena for allocation. ObjHeader** GetReturnSlotIfArena(ObjHeader** returnSlot, ObjHeader** localSlot) RUNTIME_NOTHROW; // Tries to use param's arena for allocation.