Fix using cached Kotlin subclasses of Objective-C classes (#3990)

This commit is contained in:
SvyatoslavScherbina
2020-03-18 14:17:48 +03:00
committed by GitHub
parent 5b9beec860
commit fe3057a40b
4 changed files with 39 additions and 14 deletions
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.ir.allParameters import org.jetbrains.kotlin.backend.konan.ir.allParameters
import org.jetbrains.kotlin.backend.konan.ir.isUnit import org.jetbrains.kotlin.backend.konan.ir.isUnit
import org.jetbrains.kotlin.backend.konan.isExternalObjCClass import org.jetbrains.kotlin.backend.konan.isExternalObjCClass
import org.jetbrains.kotlin.backend.konan.isKotlinObjCClass
import org.jetbrains.kotlin.backend.konan.serialization.AbstractKonanIrMangler import org.jetbrains.kotlin.backend.konan.serialization.AbstractKonanIrMangler
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.findAnnotation import org.jetbrains.kotlin.ir.util.findAnnotation
@@ -93,6 +94,14 @@ internal val IrClass.objectInstanceGetterSymbolName: String
return "kobjget:$fqNameForIrSerialization" return "kobjget:$fqNameForIrSerialization"
} }
internal val IrClass.kotlinObjCClassInfoSymbolName: String
get() {
assert (this.isExported())
assert (this.isKotlinObjCClass())
return "kobjcclassinfo:$fqNameForIrSerialization"
}
val IrFunction.functionName get() = with(KonanBinaryInterface) { functionName } val IrFunction.functionName get() = with(KonanBinaryInterface) { functionName }
val IrFunction.symbolName get() = with(KonanBinaryInterface) { symbolName } val IrFunction.symbolName get() = with(KonanBinaryInterface) { symbolName }
@@ -1005,22 +1005,19 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
error("type-checking against Kotlin classes inheriting Objective-C meta-classes isn't supported yet") error("type-checking against Kotlin classes inheriting Objective-C meta-classes isn't supported yet")
} }
val objCDeclarations = context.llvmDeclarations.forClass(irClass).objCDeclarations!! val classInfo = codegen.kotlinObjCClassInfo(irClass)
val classPointerGlobal = objCDeclarations.classPointerGlobal.llvmGlobal val classPointerGlobal = load(structGep(classInfo, 12 /* createdClass */))
val storedClass = this.load(classPointerGlobal) val storedClass = this.load(classPointerGlobal)
val storedClassIsNotNull = this.icmpNe(storedClass, kNullInt8Ptr) val storedClassIsNotNull = this.icmpNe(storedClass, kNullInt8Ptr)
return this.ifThenElse(storedClassIsNotNull, storedClass) { return this.ifThenElse(storedClassIsNotNull, storedClass) {
val newClass = call( call(
context.llvm.createKotlinObjCClass, context.llvm.createKotlinObjCClass,
listOf(objCDeclarations.classInfoGlobal.llvmGlobal), listOf(classInfo),
exceptionHandler = exceptionHandler exceptionHandler = exceptionHandler
) )
this.store(newClass, classPointerGlobal)
newClass
} }
} }
} }
@@ -66,12 +66,14 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
irClass.typeInfoPtr, irClass.typeInfoPtr,
companionObject?.typeInfoPtr ?: NullPointer(runtime.typeInfoType), companionObject?.typeInfoPtr ?: NullPointer(runtime.typeInfoType),
objCLLvmDeclarations.classPointerGlobal.pointer staticData.placeGlobal(
"kobjcclassptr:${irClass.fqNameForIrSerialization}#internal",
NullPointer(int8Type)
).pointer
) )
objCLLvmDeclarations.classInfoGlobal.setInitializer(info) objCLLvmDeclarations.classInfoGlobal.setInitializer(info)
objCLLvmDeclarations.classPointerGlobal.setInitializer(NullPointer(int8Type))
objCLLvmDeclarations.bodyOffsetGlobal.setInitializer(Int32(0)) objCLLvmDeclarations.bodyOffsetGlobal.setInitializer(Int32(0))
} }
@@ -133,3 +135,16 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
) )
} }
} }
internal fun CodeGenerator.kotlinObjCClassInfo(irClass: IrClass): LLVMValueRef {
require(irClass.isKotlinObjCClass())
return if (isExternal(irClass)) {
importGlobal(
irClass.kotlinObjCClassInfoSymbolName,
runtime.kotlinObjCClassInfo,
origin = irClass.llvmSymbolOrigin
)
} else {
context.llvmDeclarations.forClass(irClass).objCDeclarations!!.classInfoGlobal.llvmGlobal
}
}
@@ -70,7 +70,6 @@ internal class ClassLlvmDeclarations(
internal class SingletonLlvmDeclarations(val instanceStorage: AddressAccess, val instanceShadowStorage: AddressAccess?) internal class SingletonLlvmDeclarations(val instanceStorage: AddressAccess, val instanceShadowStorage: AddressAccess?)
internal class KotlinObjCClassLlvmDeclarations( internal class KotlinObjCClassLlvmDeclarations(
val classPointerGlobal: StaticData.Global,
val classInfoGlobal: StaticData.Global, val classInfoGlobal: StaticData.Global,
val bodyOffsetGlobal: StaticData.Global val bodyOffsetGlobal: StaticData.Global
) )
@@ -290,18 +289,23 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
private fun createKotlinObjCClassDeclarations(irClass: IrClass): KotlinObjCClassLlvmDeclarations { private fun createKotlinObjCClassDeclarations(irClass: IrClass): KotlinObjCClassLlvmDeclarations {
val internalName = qualifyInternalName(irClass) val internalName = qualifyInternalName(irClass)
val classPointerGlobal = staticData.createGlobal(int8TypePtr, "kobjcclassptr:$internalName") val isExported = irClass.isExported()
val classInfoSymbolName = if (isExported) {
irClass.kotlinObjCClassInfoSymbolName
} else {
"kobjcclassinfo:$internalName"
}
val classInfoGlobal = staticData.createGlobal( val classInfoGlobal = staticData.createGlobal(
context.llvm.runtime.kotlinObjCClassInfo, context.llvm.runtime.kotlinObjCClassInfo,
"kobjcclassinfo:$internalName" classInfoSymbolName,
isExported = isExported
).apply { ).apply {
setConstant(true) setConstant(true)
} }
val bodyOffsetGlobal = staticData.createGlobal(int32Type, "kobjcbodyoffs:$internalName") val bodyOffsetGlobal = staticData.createGlobal(int32Type, "kobjcbodyoffs:$internalName")
return KotlinObjCClassLlvmDeclarations(classPointerGlobal, classInfoGlobal, bodyOffsetGlobal) return KotlinObjCClassLlvmDeclarations(classInfoGlobal, bodyOffsetGlobal)
} }
override fun visitField(declaration: IrField) { override fun visitField(declaration: IrField) {