diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt index 93c27425664..219082c0d04 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt @@ -85,7 +85,16 @@ internal val IrClass.writableTypeInfoSymbolName: String return "ktypew:" + this.fqNameForIrSerialization.toString() } -internal val IrClass.objectInstanceGetterSymbolName: String +internal val IrClass.globalObjectStorageSymbolName: String + get() { + assert (this.isExported()) + assert (this.kind.isSingleton) + assert (!this.isUnit()) + + return "kobjref:$fqNameForIrSerialization" + } + +internal val IrClass.threadLocalObjectStorageGetterSymbolName: String get() { assert (this.isExported()) assert (this.kind.isSingleton) 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 112f6eb8a40..5cfa43141d6 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 @@ -901,31 +901,56 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, } } - // If object is imported - access it via getter function. - if (isExternal(irClass)) { - val valueGetterName = irClass.objectInstanceGetterSymbolName - val valueGetterFunction = LLVMGetNamedFunction(context.llvmModule, valueGetterName) ?: - LLVMAddFunction(context.llvmModule, valueGetterName, - functionType(kObjHeaderPtr, false, kObjHeaderPtrPtr)) - return call(valueGetterFunction!!, - listOf(), - resultLifetime = Lifetime.GLOBAL, - exceptionHandler = exceptionHandler) + val storageKind = irClass.storageKind(context) + + val objectPtr = if (isExternal(irClass)) { + when (storageKind) { + // If thread local object is imported - access it via getter function. + ObjectStorageKind.THREAD_LOCAL -> { + val valueGetterName = irClass.threadLocalObjectStorageGetterSymbolName + val valueGetterFunction = LLVMGetNamedFunction(context.llvmModule, valueGetterName) + ?: LLVMAddFunction(context.llvmModule, valueGetterName, + functionType(kObjHeaderPtrPtr, false)) + call(valueGetterFunction!!, + listOf(), + resultLifetime = Lifetime.GLOBAL, + exceptionHandler = exceptionHandler) + } + + // If global object is imported - import it's storage directly. + ObjectStorageKind.PERMANENT, ObjectStorageKind.SHARED -> { + val llvmType = getLLVMType(irClass.defaultType) + importGlobal( + irClass.globalObjectStorageSymbolName, + llvmType, + origin = irClass.llvmSymbolOrigin + ) + } + } + } else { + // Local globals and thread locals storage info is stored in our map. + val singleton = context.llvmDeclarations.forSingleton(irClass) + val instanceAddress = singleton.instanceStorage + instanceAddress.getAddress(this) } - val storageKind = irClass.storageKind(context) when (storageKind) { - ObjectStorageKind.SHARED -> context.llvm.sharedObjects += irClass - ObjectStorageKind.THREAD_LOCAL -> context.llvm.objects += irClass + ObjectStorageKind.SHARED -> + // If current file used a shared object, make file's (de)initializer function deinit it. + context.llvm.globalSharedObjects += objectPtr + ObjectStorageKind.THREAD_LOCAL -> + // If current file used locally defined TLS objects, make file's (de)initializer function + // init and deinit TLS. + // Note: for exported TLS objects a getter is generated in a file they're defined in. Which + // adds TLS init and deinit to that file's (de)initializer function. + if (!isExternal(irClass)) + context.llvm.fileUsesThreadLocalObjects = true ObjectStorageKind.PERMANENT -> { /* Do nothing, no need to free such an instance. */ } } - val singleton = context.llvmDeclarations.forSingleton(irClass) - val instanceAddress = singleton.instanceStorage if (storageKind == ObjectStorageKind.PERMANENT) { - return loadSlot(instanceAddress.getAddress(this), false) + return loadSlot(objectPtr, false) } - val objectPtr = instanceAddress.getAddress(this) val bbInit = basicBlock("label_init", startLocationInfo, endLocationInfo) val bbExit = basicBlock("label_continue", startLocationInfo, endLocationInfo) val objectVal = loadSlot(objectPtr, false) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 4f7f587a300..386bc1a5ed6 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -557,8 +557,8 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { val irStaticInitializers = mutableListOf() val otherStaticInitializers = mutableListOf() val fileInitializers = mutableListOf() - val objects = mutableSetOf() - val sharedObjects = mutableSetOf() + var fileUsesThreadLocalObjects = false + val globalSharedObjects = mutableSetOf() private object lazyRtFunction { operator fun provideDelegate( 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 b742d76ad2d..510312abb47 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 @@ -455,10 +455,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map - val address = context.llvmDeclarations.forSingleton(irClass).instanceStorage.getAddress( - functionGenerationContext - ) + context.llvm.globalSharedObjects.forEach { address -> storeHeapRef(codegen.kNullObjHeaderPtr, address) } ret(null) @@ -498,14 +495,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map