Do not generate getters for global singletons (#4166)
This commit is contained in:
committed by
GitHub
parent
07e6590ad3
commit
bd42c443f9
+10
-1
@@ -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)
|
||||
|
||||
+42
-17
@@ -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)
|
||||
|
||||
+2
-2
@@ -557,8 +557,8 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
val irStaticInitializers = mutableListOf<IrStaticInitializer>()
|
||||
val otherStaticInitializers = mutableListOf<LLVMValueRef>()
|
||||
val fileInitializers = mutableListOf<IrField>()
|
||||
val objects = mutableSetOf<IrClass>()
|
||||
val sharedObjects = mutableSetOf<IrClass>()
|
||||
var fileUsesThreadLocalObjects = false
|
||||
val globalSharedObjects = mutableSetOf<LLVMValueRef>()
|
||||
|
||||
private object lazyRtFunction {
|
||||
operator fun provideDelegate(
|
||||
|
||||
+23
-18
@@ -455,10 +455,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
storeHeapRef(codegen.kNullObjHeaderPtr, address)
|
||||
}
|
||||
}
|
||||
context.llvm.sharedObjects.forEach { irClass ->
|
||||
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<IrE
|
||||
override fun visitFile(declaration: IrFile) {
|
||||
// TODO: collect those two in one place.
|
||||
context.llvm.fileInitializers.clear()
|
||||
context.llvm.objects.clear()
|
||||
context.llvm.sharedObjects.clear()
|
||||
context.llvm.fileUsesThreadLocalObjects = false
|
||||
context.llvm.globalSharedObjects.clear()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
using(FileScope(declaration)) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
|
||||
if (context.llvm.fileInitializers.isEmpty() && context.llvm.objects.isEmpty() && context.llvm.sharedObjects.isEmpty())
|
||||
if (context.llvm.fileInitializers.isEmpty() && !context.llvm.fileUsesThreadLocalObjects && context.llvm.globalSharedObjects.isEmpty())
|
||||
return
|
||||
|
||||
// Create global initialization records.
|
||||
@@ -776,20 +773,28 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
val singleton = context.llvmDeclarations.forSingleton(declaration)
|
||||
val access = singleton.instanceStorage
|
||||
if (access is GlobalAddressAccess) {
|
||||
// Global objects are kept in a data segment and can be accessed by any module (if exported) and also
|
||||
// they need to be initialized statically.
|
||||
LLVMSetInitializer(access.getAddress(null), if (declaration.storageKind(context) == ObjectStorageKind.PERMANENT)
|
||||
context.llvm.staticData.createConstKotlinObject(declaration,
|
||||
*computeFields(declaration)).llvm else codegen.kNullObjHeaderPtr)
|
||||
}
|
||||
val isObjCCompanion = declaration.isCompanion && declaration.parentAsClass.isObjCClass()
|
||||
// If can be exported and can be instantiated.
|
||||
if (declaration.isExported() && !isObjCCompanion &&
|
||||
declaration.constructors.singleOrNull() { it.valueParameters.size == 0 } != null) {
|
||||
val valueGetterName = declaration.objectInstanceGetterSymbolName
|
||||
generateFunction(codegen,
|
||||
LLVMFunctionType(codegen.kObjHeaderPtr, cValuesOf(codegen.kObjHeaderPtrPtr), 1, 0)!!,
|
||||
valueGetterName) {
|
||||
val value = getObjectValue(declaration, ExceptionHandler.Caller, null, null)
|
||||
ret(value)
|
||||
} else {
|
||||
// Thread local objects are kept in a special map, so they need a getter function to be accessible
|
||||
// by other modules.
|
||||
val isObjCCompanion = declaration.isCompanion && declaration.parentAsClass.isObjCClass()
|
||||
// If can be exported and can be instantiated.
|
||||
if (declaration.isExported() && !isObjCCompanion &&
|
||||
declaration.constructors.singleOrNull() { it.valueParameters.size == 0 } != null) {
|
||||
val valueGetterName = declaration.threadLocalObjectStorageGetterSymbolName
|
||||
generateFunction(codegen,
|
||||
functionType(codegen.kObjHeaderPtrPtr, false),
|
||||
valueGetterName) {
|
||||
val value = access.getAddress(this)
|
||||
ret(value)
|
||||
}
|
||||
// Getter uses TLS object, so need to ensure that this file's (de)initializer function
|
||||
// inits and deinits TLS.
|
||||
context.llvm.fileUsesThreadLocalObjects = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-11
@@ -266,17 +266,19 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
return null
|
||||
}
|
||||
|
||||
val isExported = irClass.isExported()
|
||||
val valueGetterName = if (isExported) {
|
||||
irClass.objectInstanceGetterSymbolName
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val storageKind = irClass.storageKind(context)
|
||||
val threadLocal = storageKind == ObjectStorageKind.THREAD_LOCAL
|
||||
val symbolName = "kobjref:" + qualifyInternalName(irClass)
|
||||
val instanceAddress = addKotlinGlobal(symbolName, getLLVMType(irClass.defaultType), threadLocal = threadLocal)
|
||||
val isExported = irClass.isExported()
|
||||
val symbolName = if (isExported) {
|
||||
irClass.globalObjectStorageSymbolName
|
||||
} else {
|
||||
"kobjref:" + qualifyInternalName(irClass)
|
||||
}
|
||||
val instanceAddress = if (threadLocal) {
|
||||
addKotlinThreadLocal(symbolName, getLLVMType(irClass.defaultType))
|
||||
} else {
|
||||
addKotlinGlobal(symbolName, getLLVMType(irClass.defaultType), isExported)
|
||||
}
|
||||
|
||||
return SingletonLlvmDeclarations(instanceAddress)
|
||||
}
|
||||
@@ -319,8 +321,11 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
} else {
|
||||
// Fields are module-private, so we use internal name:
|
||||
val name = "kvar:" + qualifyInternalName(declaration)
|
||||
val storage = addKotlinGlobal(
|
||||
name, getLLVMType(declaration.type), threadLocal = declaration.storageKind == FieldStorageKind.THREAD_LOCAL)
|
||||
val storage = if (declaration.storageKind == FieldStorageKind.THREAD_LOCAL) {
|
||||
addKotlinThreadLocal(name, getLLVMType(declaration.type))
|
||||
} else {
|
||||
addKotlinGlobal(name, getLLVMType(declaration.type), isExported = false)
|
||||
}
|
||||
|
||||
this.staticFields[declaration] = StaticFieldLlvmDeclarations(storage)
|
||||
}
|
||||
|
||||
+19
-23
@@ -238,18 +238,13 @@ internal fun getGlobalType(ptrToGlobal: LLVMValueRef): LLVMTypeRef {
|
||||
return LLVMGetElementType(ptrToGlobal.type)!!
|
||||
}
|
||||
|
||||
internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported: Boolean,
|
||||
threadLocal: Boolean = false): LLVMValueRef {
|
||||
internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): LLVMValueRef {
|
||||
if (isExported)
|
||||
assert(LLVMGetNamedGlobal(context.llvmModule, name) == null)
|
||||
val result = LLVMAddGlobal(context.llvmModule, type, name)!!
|
||||
if (threadLocal)
|
||||
LLVMSetThreadLocalMode(result, context.llvm.tlsMode)
|
||||
return result
|
||||
return LLVMAddGlobal(context.llvmModule, type, name)!!
|
||||
}
|
||||
|
||||
internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin: CompiledKlibModuleOrigin,
|
||||
threadLocal: Boolean = false): LLVMValueRef {
|
||||
internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin: CompiledKlibModuleOrigin): LLVMValueRef {
|
||||
|
||||
context.llvm.imports.add(origin)
|
||||
|
||||
@@ -257,11 +252,9 @@ internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin:
|
||||
return if (found != null) {
|
||||
assert (getGlobalType(found) == type)
|
||||
assert (LLVMGetInitializer(found) == null) { "$name is already declared in the current module" }
|
||||
if (threadLocal)
|
||||
assert(LLVMGetThreadLocalMode(found) == context.llvm.tlsMode)
|
||||
found
|
||||
} else {
|
||||
addGlobal(name, type, false, threadLocal)
|
||||
addGlobal(name, type, isExported = false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,20 +275,23 @@ internal class TLSAddressAccess(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ContextUtils.addKotlinGlobal(name: String, type: LLVMTypeRef, threadLocal: Boolean): AddressAccess {
|
||||
if (threadLocal) {
|
||||
return if (isObjectType(type)) {
|
||||
val index = context.llvm.tlsCount++
|
||||
TLSAddressAccess(context, index)
|
||||
} else {
|
||||
GlobalAddressAccess(LLVMAddGlobal(context.llvmModule, type, name)!!.also {
|
||||
LLVMSetThreadLocalMode(it, context.llvm.tlsMode)
|
||||
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
|
||||
})
|
||||
}
|
||||
internal fun ContextUtils.addKotlinThreadLocal(name: String, type: LLVMTypeRef): AddressAccess {
|
||||
return if (isObjectType(type)) {
|
||||
val index = context.llvm.tlsCount++
|
||||
TLSAddressAccess(context, index)
|
||||
} else {
|
||||
// TODO: This will break if Workers get decoupled from host threads.
|
||||
GlobalAddressAccess(LLVMAddGlobal(context.llvmModule, type, name)!!.also {
|
||||
LLVMSetThreadLocalMode(it, context.llvm.tlsMode)
|
||||
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ContextUtils.addKotlinGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): AddressAccess {
|
||||
return GlobalAddressAccess(LLVMAddGlobal(context.llvmModule, type, name)!!.also {
|
||||
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
|
||||
if (!isExported)
|
||||
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user