Native: don't use aliases for kclass:* globals, fix KT-61417
Currently, when generating a TypeInfo with a vtable attached, the K/N compiler generates two globals to the resulting LLVM module: - "ktypeglobal:$fqName#internal" -- an internal global of the aggregate type (TypeInfo+vtable) - "kclass:$fqName" -- an internal or hidden alias pointing to the TypeInfo part of that global The reason for emitting two globals is to have everything strict-typed, since other LLVM modules might import the kclass as a TypeInfo. Importing an aggregate TypeInfo+vtable global as a TypeInfo global works too, of course. It is just a little bit less clean. The new Xcode 15 linker now emits symbols for the ktypeglobal to the symbol table, including an STSYM. This happens for classes compiled to cache, when the kclass is hidden, not internal. The problem is: for some reason, such an STSYM for "ktypeglobal:kotlin.String#internal" makes lldb find a wrong address (0xffffffffffffffff) for "kclass:kotlin.String", despite those being two different symbol names. This seems to be related to them having the same address though. The K/N lldb script, konan_lldb.py, uses "kclass:kotlin.String" to determine if an object is a string, in order to display it properly. Therefore, using the new Xcode 15 linker when compiling with caches makes the debugger unable to display string variables properly. As a side effect, this also breaks displaying array-typed variables (because the script first checks if an object is a string). This commit fixes this by removing ktypeglobals completely, making the compiler emit only a kclass as an aggregate global directly. Now, there are other ways to fix the problem. For example, making the ktypeglobal private instead of internal, or making konan_lldb.py use a runtime function instead of querying "kclass:kotlin.String" directly. But it seems that LLVM aliases are not common on darwin platforms. For example, Clang doesn't support `__attribute__((alias(...)))` on these platforms. So it is safer to just stop using aliases here. ^KT-61417
This commit is contained in:
committed by
Space Team
parent
070f0197fc
commit
4774912fdc
+20
-16
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user