From fe3057a40b7d4280888e2cb12abdcd6ce8c6dcf7 Mon Sep 17 00:00:00 2001 From: SvyatoslavScherbina Date: Wed, 18 Mar 2020 14:17:48 +0300 Subject: [PATCH] Fix using cached Kotlin subclasses of Objective-C classes (#3990) --- .../backend/konan/llvm/BinaryInterface.kt | 9 +++++++++ .../backend/konan/llvm/CodeGenerator.kt | 11 ++++------- .../llvm/KotlinObjCClassInfoGenerator.kt | 19 +++++++++++++++++-- .../backend/konan/llvm/LlvmDeclarations.kt | 14 +++++++++----- 4 files changed, 39 insertions(+), 14 deletions(-) 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 f5664302eb5..93c27425664 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 @@ -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.isUnit 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.ir.declarations.* import org.jetbrains.kotlin.ir.util.findAnnotation @@ -93,6 +94,14 @@ internal val IrClass.objectInstanceGetterSymbolName: String 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.symbolName get() = with(KonanBinaryInterface) { symbolName } 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 152c95ddb7b..ef90876c7b7 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 @@ -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") } - val objCDeclarations = context.llvmDeclarations.forClass(irClass).objCDeclarations!! - val classPointerGlobal = objCDeclarations.classPointerGlobal.llvmGlobal + val classInfo = codegen.kotlinObjCClassInfo(irClass) + val classPointerGlobal = load(structGep(classInfo, 12 /* createdClass */)) val storedClass = this.load(classPointerGlobal) val storedClassIsNotNull = this.icmpNe(storedClass, kNullInt8Ptr) return this.ifThenElse(storedClassIsNotNull, storedClass) { - val newClass = call( + call( context.llvm.createKotlinObjCClass, - listOf(objCDeclarations.classInfoGlobal.llvmGlobal), + listOf(classInfo), exceptionHandler = exceptionHandler ) - - this.store(newClass, classPointerGlobal) - newClass } } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt index 20643f1f19c..140a72dd1c0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt @@ -66,12 +66,14 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con irClass.typeInfoPtr, companionObject?.typeInfoPtr ?: NullPointer(runtime.typeInfoType), - objCLLvmDeclarations.classPointerGlobal.pointer + staticData.placeGlobal( + "kobjcclassptr:${irClass.fqNameForIrSerialization}#internal", + NullPointer(int8Type) + ).pointer ) objCLLvmDeclarations.classInfoGlobal.setInitializer(info) - objCLLvmDeclarations.classPointerGlobal.setInitializer(NullPointer(int8Type)) objCLLvmDeclarations.bodyOffsetGlobal.setInitializer(Int32(0)) } @@ -132,4 +134,17 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con it.llvmFunction ) } +} + +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 + } } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt index 60da5877af1..8f28933bd55 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt @@ -70,7 +70,6 @@ internal class ClassLlvmDeclarations( internal class SingletonLlvmDeclarations(val instanceStorage: AddressAccess, val instanceShadowStorage: AddressAccess?) internal class KotlinObjCClassLlvmDeclarations( - val classPointerGlobal: StaticData.Global, val classInfoGlobal: StaticData.Global, val bodyOffsetGlobal: StaticData.Global ) @@ -290,18 +289,23 @@ private class DeclarationsGeneratorVisitor(override val context: Context) : private fun createKotlinObjCClassDeclarations(irClass: IrClass): KotlinObjCClassLlvmDeclarations { 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( context.llvm.runtime.kotlinObjCClassInfo, - "kobjcclassinfo:$internalName" + classInfoSymbolName, + isExported = isExported ).apply { setConstant(true) } val bodyOffsetGlobal = staticData.createGlobal(int32Type, "kobjcbodyoffs:$internalName") - return KotlinObjCClassLlvmDeclarations(classPointerGlobal, classInfoGlobal, bodyOffsetGlobal) + return KotlinObjCClassLlvmDeclarations(classInfoGlobal, bodyOffsetGlobal) } override fun visitField(declaration: IrField) {