diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt index 75dc00ac519..c585e00c831 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt @@ -219,31 +219,35 @@ private class DeclarationsGeneratorVisitor(override val generationState: NativeG if (declaration.typeInfoHasVtableAttached) { // Create the special global consisting of TypeInfo and vtable. - val typeInfoGlobalName = "ktypeglobal:$internalName" - val typeInfoWithVtableType = llvm.structType( runtime.typeInfoType, LLVMArrayType(llvm.int8PtrType, context.getLayoutBuilder(declaration).vtableEntries.size)!! ) - typeInfoGlobal = staticData.createGlobal(typeInfoWithVtableType, typeInfoGlobalName, isExported = false) + typeInfoGlobal = staticData.createGlobal(typeInfoWithVtableType, typeInfoSymbolName, declaration.isExported()) - val llvmTypeInfoPtr = LLVMAddAlias(llvm.module, - kTypeInfoPtr, - typeInfoGlobal.pointer.getElementPtr(llvm, 0).llvm, - typeInfoSymbolName)!! + // Other LLVM modules might import this global as a TypeInfo global. + // This works only if there is no gap between the beginning of the global and the TypeInfo part, + // which should always be the case, since it is the zeroth element. + // Still, better be safe than sorry, checking this explicitly: + val typeInfoOffsetInGlobal = LLVMOffsetOfElement(llvmTargetData, typeInfoWithVtableType, 0) + check(typeInfoOffsetInGlobal == 0L) { "Offset for $typeInfoSymbolName TypeInfo is $typeInfoOffsetInGlobal" } - if (declaration.isExported()) { - if (llvmTypeInfoPtr.name != typeInfoSymbolName) { - // So alias name has been mangled by LLVM to avoid name clash. - throw IllegalArgumentException("Global '$typeInfoSymbolName' already exists") - } - } else { - if (!context.config.producePerFileCache || declaration !in generationState.constructedFromExportedInlineFunctions) - LLVMSetLinkage(llvmTypeInfoPtr, LLVMLinkage.LLVMInternalLinkage) + if (context.config.producePerFileCache && declaration in generationState.constructedFromExportedInlineFunctions) { + // This is required because internal inline functions can access private classes. + // So, in the generated code, the class type info can be accessed outside the file. + // With per-file caches involved, this can mean accessing from a different object file. + // Therefore, the class type info has to have external linkage in that case. + // Check e.g. `nestedInPrivateClass2.kt` test (it should fail if you remove setting linkage to external). + // + // This case should be reflected in the `isExported` parameter of `createGlobal` above, instead of + // patching the linkage ad hoc. + // The problem is: such globals in fact can have clashing names, which makes createGlobal fail. + // See https://youtrack.jetbrains.com/issue/KT-61428. + typeInfoGlobal.setLinkage(LLVMLinkage.LLVMExternalLinkage) } - typeInfoPtr = constPointer(llvmTypeInfoPtr) + typeInfoPtr = typeInfoGlobal.pointer.getElementPtr(llvm, 0) } else { typeInfoGlobal = staticData.createGlobal(runtime.typeInfoType, diff --git a/kotlin-native/backend.native/tests/filecheck/constants_merge.kt b/kotlin-native/backend.native/tests/filecheck/constants_merge.kt index 9533aa65a40..7d806a27448 100644 --- a/kotlin-native/backend.native/tests/filecheck/constants_merge.kt +++ b/kotlin-native/backend.native/tests/filecheck/constants_merge.kt @@ -5,14 +5,14 @@ import kotlin.reflect.* -// CHECK: [[REG_FOR_1024:@[0-9]+]] = internal unnamed_addr constant { %struct.ObjHeader, i32 } { %struct.ObjHeader { %struct.TypeInfo* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.TypeInfo* @"kclass:kotlin.Int" to i8*), i32 1) to %struct.TypeInfo*) }, i32 1024 } -// CHECK-NOT: internal unnamed_addr constant { %struct.ObjHeader, i32 } { %struct.ObjHeader { %struct.TypeInfo* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.TypeInfo* @"kclass:kotlin.Int" to i8*), i32 1) to %struct.TypeInfo*) }, i32 1024 } +// CHECK: [[REG_FOR_1024:@[0-9]+]] = internal unnamed_addr constant { %struct.ObjHeader, i32 } { %struct.ObjHeader { %struct.TypeInfo* {{.*}} }, i32 1024 } +// CHECK-NOT: internal unnamed_addr constant { %struct.ObjHeader, i32 } { %struct.ObjHeader { %struct.TypeInfo* {{.*}} }, i32 1024 } -// CHECK: internal unnamed_addr constant { %struct.ArrayHeader, [3 x %struct.ObjHeader*] } { %struct.ArrayHeader { %struct.TypeInfo* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.TypeInfo* @"kclass:kotlin.Array" to i8*), i32 1) to %struct.TypeInfo*), i32 3 }, [3 x %struct.ObjHeader*] [%struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_1024]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_2048:@[0-9]+]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_4096:@[0-9]+]], i32 0, i32 0)] } -// CHECK-NOT: internal unnamed_addr constant { %struct.ArrayHeader, [3 x %struct.ObjHeader*] } { %struct.ArrayHeader { %struct.TypeInfo* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.TypeInfo* @"kclass:kotlin.Array" to i8*), i32 1) to %struct.TypeInfo*), i32 3 }, [3 x %struct.ObjHeader*] [%struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_1024]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_2048]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_4096]], i32 0, i32 0)] } +// CHECK: internal unnamed_addr constant { %struct.ArrayHeader, [3 x %struct.ObjHeader*] } { %struct.ArrayHeader { %struct.TypeInfo* {{.*}}, i32 3 }, [3 x %struct.ObjHeader*] [%struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_1024]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_2048:@[0-9]+]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_4096:@[0-9]+]], i32 0, i32 0)] } +// CHECK-NOT: internal unnamed_addr constant { %struct.ArrayHeader, [3 x %struct.ObjHeader*] } { %struct.ArrayHeader { %struct.TypeInfo* {{.*}}, i32 3 }, [3 x %struct.ObjHeader*] [%struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_1024]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_2048:@[0-9]+]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i32 }, { %struct.ObjHeader, i32 }* [[REG_FOR_4096:@[0-9]+]], i32 0, i32 0)] } -// CHECK: internal unnamed_addr constant { %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader*, i1 } { %struct.ObjHeader { %struct.TypeInfo* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.TypeInfo* @"kclass:kotlin.native.internal.KTypeImpl" to i8*), i32 1) to %struct.TypeInfo*) }, %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i8* }, { %struct.ObjHeader, i8* }* [[REG_FOR_CLASSIFIER_FIELD:@[0-9]+]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader* }, { %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader* }* [[REG_FOR_ARGUMENTS_FIELD:@[0-9]+]], i32 0, i32 0), i1 false } -// CHECK-NOT: internal unnamed_addr constant { %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader*, i1 } { %struct.ObjHeader { %struct.TypeInfo* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.TypeInfo* @"kclass:kotlin.native.internal.KTypeImpl" to i8*), i32 1) to %struct.TypeInfo*) }, %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i8* }, { %struct.ObjHeader, i8* }* [[REG_FOR_CLASSIFIER_FIELD]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader* }, { %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader* }* [[REG_FOR_ARGUMENTS_FIELD]], i32 0, i32 0), i1 false } +// CHECK: internal unnamed_addr constant { %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader*, i1 } { %struct.ObjHeader { %struct.TypeInfo* {{.*}} }, %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i8* }, { %struct.ObjHeader, i8* }* [[REG_FOR_CLASSIFIER_FIELD:@[0-9]+]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader* }, { %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader* }* [[REG_FOR_ARGUMENTS_FIELD:@[0-9]+]], i32 0, i32 0), i1 false } +// CHECK-NOT: internal unnamed_addr constant { %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader*, i1 } { %struct.ObjHeader { %struct.TypeInfo* {{.*}} }, %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, i8* }, { %struct.ObjHeader, i8* }* [[REG_FOR_CLASSIFIER_FIELD:@[0-9]+]], i32 0, i32 0), %struct.ObjHeader* getelementptr inbounds ({ %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader* }, { %struct.ObjHeader, %struct.ObjHeader*, %struct.ObjHeader* }* [[REG_FOR_ARGUMENTS_FIELD:@[0-9]+]], i32 0, i32 0), i1 false } fun main() { println(1024)