From 28ab39f5937ced1513e5f12028064de00745cdd8 Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Tue, 25 Dec 2018 18:31:04 +0300 Subject: [PATCH] Better debug locations logic. (#2496) --- .../jetbrains/kotlin/backend/konan/Context.kt | 5 ++ .../kotlin/backend/konan/OutputFiles.kt | 6 +-- .../kotlin/backend/konan/ir/KonanIr.kt | 27 +++++----- .../backend/konan/llvm/CodeGenerator.kt | 22 ++++---- .../kotlin/backend/konan/llvm/DebugUtils.kt | 31 ++++++----- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 22 ++++---- .../backend/konan/lower/DelegationLowering.kt | 9 ++-- .../konan/lower/SuspendFunctionsLowering.kt | 5 +- .../backend/konan/lower/TestProcessor.kt | 51 ++++++++++--------- .../backend/konan/optimizations/DFGBuilder.kt | 3 +- .../org/jetbrains/kotlin/KonanTest.groovy | 4 +- 11 files changed, 103 insertions(+), 82 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 3b8a1b0baf5..9d1f39fd842 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 @@ -52,6 +52,11 @@ import java.lang.System.out import kotlin.LazyThreadSafetyMode.PUBLICATION import kotlin.reflect.KProperty +/** + * Offset for synthetic elements created by lowerings and not attributable to other places in the source code. + */ +internal const val SYNTHETIC_OFFSET = -2 + internal class SpecialDeclarationsFactory(val context: Context) { private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) } private val outerThisFields = mutableMapOf() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt index 941ad7dd600..3f8ff2a649d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.konan.util.visibleName /** - * Creates and stores terminal compiler outputs + * Creates and stores terminal compiler outputs. */ class OutputFiles(outputPath: String?, target: KonanTarget, produce: CompilerOutputKind) { @@ -24,13 +24,13 @@ class OutputFiles(outputPath: String?, target: KonanTarget, produce: CompilerOut val outputName = outputPath?.removeSuffixIfPresent(suffix) ?: produce.visibleName /** - * Header file for dynamic library + * Header file for dynamic library. */ val cAdapterHeader by lazy { File("${outputName}_api.h") } val cAdapterDef by lazy { File("${outputName}_symbols.def") } /** - * Main compiler's output file + * Main compiler's output file. */ val mainFile = outputName .prefixBaseNameIfNot(prefix) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt index 34591d312bb..6475d239e02 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt @@ -5,30 +5,27 @@ package org.jetbrains.kotlin.backend.konan.ir +import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.SourceRangeInfo +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.impl.IrCallWithIndexedArgumentsBase import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase import org.jetbrains.kotlin.ir.expressions.impl.IrTerminalDeclarationReferenceBase -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrFileSymbol -import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.types.KotlinType //-----------------------------------------------------------------------------// /** @@ -49,12 +46,19 @@ class NaiveSourceBasedFileEntryImpl(override val name: String) : SourceManager.F init { val file = File(name) if (file.isFile) { + // TODO: could be incorrect, if file is not in system's line terminator format. + // Maybe use (0..document.lineCount - 1) + // .map { document.getLineStartOffset(it) } + // .toIntArray() + // as in PSI. + val separatorLength = System.lineSeparator().length val buffer = mutableListOf() var currentOffset = 0 file.forEachLine { line -> buffer.add(currentOffset) - currentOffset += line.length + currentOffset += line.length + separatorLength } + buffer.add(currentOffset) lineStartOffsets = buffer.toIntArray() } else { lineStartOffsets = IntArray(0) @@ -64,19 +68,18 @@ class NaiveSourceBasedFileEntryImpl(override val name: String) : SourceManager.F //-------------------------------------------------------------------------// override fun getLineNumber(offset: Int): Int { + assert(offset != UNDEFINED_OFFSET) + if (offset == SYNTHETIC_OFFSET) return 0 val index = lineStartOffsets.binarySearch(offset) - return if (index >= 0) index else -index - 1 + return if (index >= 0) index else -index - 2 } //-------------------------------------------------------------------------// override fun getColumnNumber(offset: Int): Int { + assert(offset != UNDEFINED_OFFSET) + if (offset == SYNTHETIC_OFFSET) return 0 var lineNumber = getLineNumber(offset) - if (lineNumber >= lineStartOffsets.size) { - lineNumber = lineStartOffsets.size - 1 - } - if (lineNumber < 0) lineNumber = 0 - if (lineStartOffsets.size == 0) return offset return offset - lineStartOffsets[lineNumber] } 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 5f89fccfe95..4fc209f7794 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 @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.* import llvm.* +import org.jetbrains.kotlin.backend.common.ir.ir2string import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.backend.konan.irasdescriptors.* @@ -130,8 +131,9 @@ internal inline fun generateFunction(codegen: CodeGenerator, } -internal inline fun generateFunction(codegen: CodeGenerator, function: LLVMValueRef, code:FunctionGenerationContext.(FunctionGenerationContext) -> R) { - generateFunctionBody(FunctionGenerationContext(function, codegen), code) +internal inline fun generateFunction(codegen: CodeGenerator, function: LLVMValueRef, + code:FunctionGenerationContext.(FunctionGenerationContext) -> R) { + generateFunctionBody(FunctionGenerationContext(function, codegen, null, null), code) } internal inline fun generateFunction( @@ -145,7 +147,9 @@ internal inline fun generateFunction( return function } -inline private fun generateFunctionBody(functionGenerationContext: FunctionGenerationContext, code: FunctionGenerationContext.(FunctionGenerationContext) -> R) { +inline private fun generateFunctionBody( + functionGenerationContext: FunctionGenerationContext, + code: FunctionGenerationContext.(FunctionGenerationContext) -> R) { functionGenerationContext.prologue() functionGenerationContext.code(functionGenerationContext) if (!functionGenerationContext.isAfterTerminator()) @@ -155,10 +159,11 @@ inline private fun generateFunctionBody(functionGenerationContext: FunctionG } internal class FunctionGenerationContext(val function: LLVMValueRef, - val codegen:CodeGenerator, - startLocation:LocationInfo? = null, - endLocation:LocationInfo? = null, - internal val functionDescriptor: FunctionDescriptor? = null):ContextUtils { + val codegen: CodeGenerator, + startLocation: LocationInfo?, + endLocation: LocationInfo?, + internal val functionDescriptor: FunctionDescriptor? = null): ContextUtils { + override val context = codegen.context val vars = VariableManager(this) private val basicBlockToLastLocation = mutableMapOf() @@ -208,7 +213,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, return bb } - fun basicBlock(name:String = "label_" , locationInfo:LocationInfo?):LLVMBasicBlockRef { + fun basicBlock(name:String = "label_" , locationInfo:LocationInfo?): LLVMBasicBlockRef { val result = LLVMInsertBasicBlock(this.currentBlock, name)!! update(result, locationInfo) LLVMMoveBasicBlockAfter(result, this.currentBlock) @@ -359,7 +364,6 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, val rargs = args.toCValues() if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ && isFunctionNoUnwind(llvmFunction)) { - return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!! } else { val unwind = when (exceptionHandler) { 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 3b706b8331d..c949157f556 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 @@ -8,12 +8,14 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.allocArrayOf import kotlinx.cinterop.memScoped import llvm.* +import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.KonanConfig import org.jetbrains.kotlin.backend.konan.KonanConfigKeys import org.jetbrains.kotlin.backend.konan.irasdescriptors.FunctionDescriptor import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.ir.SourceManager.FileEntry +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.konan.KonanVersion import org.jetbrains.kotlin.konan.file.File @@ -81,19 +83,26 @@ internal class DebugInfo internal constructor(override val context: Context):Con val otherTypeSize = LLVMSizeOfTypeInBits(llvmTargetData, otherLlvmType) val otherTypeAlignment = LLVMPreferredAlignmentOfType(llvmTargetData, otherLlvmType) } + /** * File entry starts offsets from zero while dwarf number lines/column starting from 1. */ -private fun FileEntry.location(offset:Int, offsetToNumber:(Int) -> Int):Int { - return if (offset < 0) 0 // lldb uses 1-based unsigned integers, so 0 is "no-info" - else offsetToNumber(offset) + 1 +private val NO_SOURCE_FILE = "no source file" +private fun FileEntry.location(offset: Int, offsetToNumber: (Int) -> Int): Int { + assert(offset != UNDEFINED_OFFSET) + // Part "name.isEmpty() || name == NO_SOURCE_FILE" is an awful hack, @minamoto, please fix properly. + if (offset == SYNTHETIC_OFFSET || name.isEmpty() || name == NO_SOURCE_FILE) return 1 + // lldb uses 1-based unsigned integers, so 0 is "no-info". + val result = offsetToNumber(offset) + 1 + assert(result != 0) + return result } internal fun FileEntry.line(offset: Int) = location(offset, this::getLineNumber) internal fun FileEntry.column(offset: Int) = location(offset, this::getColumnNumber) -internal data class FileAndFolder(val file:String, val folder:String) { +internal data class FileAndFolder(val file: String, val folder: String) { companion object { val NOFILE = FileAndFolder("-", "") } @@ -109,7 +118,6 @@ internal fun String?.toFileAndFolder():FileAndFolder { internal fun generateDebugInfoHeader(context: Context) { if (context.shouldContainDebugInfo()) { - val path = context.config.outputFile .toFileAndFolder() @Suppress("UNCHECKED_CAST") @@ -150,7 +158,7 @@ internal fun generateDebugInfoHeader(context: Context) { } @Suppress("UNCHECKED_CAST") -internal fun KotlinType.dwarfType(context:Context, targetData:LLVMTargetDataRef): DITypeOpaqueRef { +internal fun KotlinType.dwarfType(context: Context, targetData: LLVMTargetDataRef): DITypeOpaqueRef { when { KotlinBuiltIns.isPrimitiveType(this) -> return debugInfoBaseType(context, targetData, this.getJetTypeFqName(false), llvmType(context), encoding(context).value.toInt()) else -> { @@ -186,7 +194,6 @@ internal fun KotlinType.diType(context: Context, llvmTargetData: LLVMTargetDataR dwarfType(context, llvmTargetData) } - @Suppress("UNCHECKED_CAST") private fun debugInfoBaseType(context:Context, targetData:LLVMTargetDataRef, typeName:String, type:LLVMTypeRef, encoding:Int) = DICreateBasicType( context.debugInfo.builder, typeName, @@ -205,14 +212,12 @@ internal fun KotlinType.alignment(context:Context) = context.debugInfo.llvmTypeA internal fun KotlinType.llvmType(context:Context): LLVMTypeRef = context.debugInfo.llvmTypes.getOrDefault(this, context.debugInfo.otherLlvmType) -private fun or(v:T, vararg p:(T)->Boolean):Boolean = p.any{it(v)} - -internal fun KotlinType.encoding(context:Context):DwarfTypeKind = when { +internal fun KotlinType.encoding(context: Context): DwarfTypeKind = when { this in context.debugInfo.intTypes -> DwarfTypeKind.DW_ATE_signed this in context.debugInfo.realTypes -> DwarfTypeKind.DW_ATE_float - KotlinBuiltIns.isBoolean(this) -> DwarfTypeKind.DW_ATE_boolean - KotlinBuiltIns.isChar(this) -> DwarfTypeKind.DW_ATE_unsigned - (!KotlinBuiltIns.isPrimitiveType(this)) -> DwarfTypeKind.DW_ATE_address + KotlinBuiltIns.isBoolean(this) -> DwarfTypeKind.DW_ATE_boolean + KotlinBuiltIns.isChar(this) -> DwarfTypeKind.DW_ATE_unsigned + (!KotlinBuiltIns.isPrimitiveType(this)) -> DwarfTypeKind.DW_ATE_address else -> TODO(toString()) } 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 a8a91668ac4..072b1e51817 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 @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.SourceFile import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.getArguments +import org.jetbrains.kotlin.ir.util.getContainingFile import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid @@ -655,12 +657,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map { val thisReceiver = (descriptor as ConstructorDescriptor).constructedClass.thisReceiver!! - val thiz = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, thisReceiver.type, + val thiz = IrGetValueImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, thisReceiver.type, thisReceiver.symbol) val arguments = listOf(thiz) + value.getArguments().map { it.second } DataFlowIR.Node.StaticCall( diff --git a/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy b/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy index 75ad85600c1..319becddbd6 100644 --- a/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy +++ b/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy @@ -575,8 +575,8 @@ class RunInteropKonanTest extends KonanTest { List linkerArguments = interopConf.linkerOpts // TODO: add arguments from .def file - List compilerArguments = ["-library", interopBc, "-nativelibrary", interopStubsBc] + - linkerArguments.collectMany { ["-linkerOpts", it] } + List compilerArguments = ["-library", interopBc, "-native-library", interopStubsBc] + + linkerArguments.collectMany { ["-linker-options", it] } runCompiler(filesToCompile, exe, compilerArguments) }