From 4080a852e1c97aa3fc321a56ca73d9ce4d7dfe36 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Thu, 28 Jan 2021 12:46:32 +0300 Subject: [PATCH] Add selector and method bridge to relevant ObjCMethodSpec types This helps to drop usages of obsolete "IrDeclaration.descriptor" from ObjCExportCodeGenerator --- .../objcexport/ObjCExportCodeGenerator.kt | 97 ++++++++++--------- .../konan/objcexport/ObjCExportCodeSpec.kt | 42 ++++++-- 2 files changed, 85 insertions(+), 54 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index a90df06e549..ea524cd0c33 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -24,6 +24,8 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrVararg import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.konan.target.Family @@ -373,8 +375,8 @@ internal class ObjCExportCodeGenerator( methods = listOf("equals", "hashCode", "toString").map { name -> symbols.any.owner.simpleFunctions().single { it.name == Name.identifier(name) } }.map { - require(mapper.shouldBeExposed(it.descriptor)) - ObjCMethodForKotlinMethod(it.symbol) + val baseMethod = createObjCMethodSpecBaseMethod(mapper, namer, it.symbol, it.descriptor) + ObjCMethodForKotlinMethod(baseMethod) }, categoryMethods = emptyList(), superClassNotAny = null @@ -957,11 +959,11 @@ private fun ObjCExportCodeGenerator.generateObjCImpForArrayConstructor( // TODO: cache bridges. private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge( irFunction: IrFunction, - baseIrFunction: IrFunction + baseMethod: ObjCMethodSpec.BaseMethod ): ConstPointer { - val baseMethod = baseIrFunction.descriptor + val baseIrFunction = baseMethod.symbol.owner - val methodBridge = mapper.bridgeMethod(baseMethod) + val methodBridge = baseMethod.bridge val parameterToBase = irFunction.allParameters.zip(baseIrFunction.allParameters).toMap() @@ -991,7 +993,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge( MethodBridgeReceiver.Instance -> kotlinReferenceToObjC(parameters[parameter]!!) MethodBridgeSelector -> { - val selector = namer.getSelector(baseMethod) + val selector = baseMethod.selector // Selector is referenced thus should be defined to avoid false positive non-public API rejection: selectorsToDefine[selector] = methodBridge genSelector(selector) @@ -1022,7 +1024,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge( val targetResult = callFromBridge(objcMsgSend, objCArgs) - assert(baseMethod !is ConstructorDescriptor) + assert(baseMethod.symbol !is IrConstructorSymbol) fun rethrow() { val error = load(errorOutPtr!!) @@ -1120,14 +1122,14 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge( private fun ObjCExportCodeGenerator.createReverseAdapter( irFunction: IrFunction, - baseMethod: IrFunction, + baseMethod: ObjCMethodSpec.BaseMethod, functionName: String, vtableIndex: Int?, itablePlace: ClassLayoutBuilder.InterfaceTablePlace? ): ObjCExportCodeGenerator.KotlinToObjCMethodAdapter { val nameSignature = functionName.localHash.value - val selector = namer.getSelector(baseMethod.descriptor) + val selector = baseMethod.selector val kotlinToObjC = generateKotlinToObjCBridge( irFunction, @@ -1141,51 +1143,51 @@ private fun ObjCExportCodeGenerator.createReverseAdapter( } private fun ObjCExportCodeGenerator.createMethodVirtualAdapter( - baseMethod: IrFunction + baseMethod: ObjCMethodSpec.BaseMethod ): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter { - assert(mapper.isBaseMethod(baseMethod.descriptor)) - - val selector = namer.getSelector(baseMethod.descriptor) - - val methodBridge = mapper.bridgeMethod(baseMethod.descriptor) - val imp = generateObjCImp(baseMethod, baseMethod, methodBridge, isVirtual = true) + val selector = baseMethod.selector + val methodBridge = baseMethod.bridge + val irFunction = baseMethod.symbol.owner + val imp = generateObjCImp(irFunction, irFunction, methodBridge, isVirtual = true) return objCToKotlinMethodAdapter(selector, methodBridge, imp) } private fun ObjCExportCodeGenerator.createMethodAdapter( implementation: IrFunction?, - baseMethod: IrFunction + baseMethod: ObjCMethodSpec.BaseMethod<*> ) = createMethodAdapter(DirectAdapterRequest(implementation, baseMethod)) private fun ObjCExportCodeGenerator.createFinalMethodAdapter( - irFunction: IrSimpleFunction + baseMethod: ObjCMethodSpec.BaseMethod ): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter { + val irFunction = baseMethod.symbol.owner require(irFunction.modality == Modality.FINAL) - return createMethodAdapter(irFunction, irFunction) + return createMethodAdapter(irFunction, baseMethod) } private fun ObjCExportCodeGenerator.createMethodAdapter( request: DirectAdapterRequest ): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter = this.directMethodAdapters.getOrPut(request) { - val selectorName = namer.getSelector(request.base.descriptor) - val methodBridge = mapper.bridgeMethod(request.base.descriptor) + val selectorName = request.base.selector + val methodBridge = request.base.bridge - val imp = generateObjCImp(request.implementation, request.base, methodBridge) + val imp = generateObjCImp(request.implementation, request.base.symbol.owner, methodBridge) objCToKotlinMethodAdapter(selectorName, methodBridge, imp) } private fun ObjCExportCodeGenerator.createConstructorAdapter( - irConstructor: IrConstructor -): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter = createMethodAdapter(irConstructor, irConstructor) + baseMethod: ObjCMethodSpec.BaseMethod +): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter = createMethodAdapter(baseMethod.symbol.owner, baseMethod) private fun ObjCExportCodeGenerator.createArrayConstructorAdapter( - irConstructor: IrConstructor + baseMethod: ObjCMethodSpec.BaseMethod ): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter { - val selectorName = namer.getSelector(irConstructor.descriptor) - val methodBridge = mapper.bridgeMethod(irConstructor.descriptor) + val selectorName = baseMethod.selector + val methodBridge = baseMethod.bridge + val irConstructor = baseMethod.symbol.owner val imp = generateObjCImpForArrayConstructor(irConstructor, methodBridge) return objCToKotlinMethodAdapter(selectorName, methodBridge, imp) @@ -1217,7 +1219,7 @@ private fun ObjCExportCodeGenerator.createTypeAdapterForFileClass( ): ObjCExportCodeGenerator.ObjCTypeAdapter { val name = fileClass.binaryName - val adapters = fileClass.methods.map { createFinalMethodAdapter(it.baseMethod.owner) } + val adapters = fileClass.methods.map { createFinalMethodAdapter(it.baseMethod) } return ObjCTypeAdapter( irClass = null, @@ -1246,10 +1248,10 @@ private fun ObjCExportCodeGenerator.createTypeAdapter( type.methods.forEach { when (it) { is ObjCInitMethodForKotlinConstructor -> { - adapters += createConstructorAdapter(it.irConstructorSymbol.owner) + adapters += createConstructorAdapter(it.baseMethod) } is ObjCFactoryMethodForKotlinArrayConstructor -> { - classAdapters += createArrayConstructorAdapter(it.irConstructorSymbol.owner) + classAdapters += createArrayConstructorAdapter(it.baseMethod) } is ObjCGetterForKotlinEnumEntry -> { classAdapters += createEnumEntryAdapter(it.irEnumEntrySymbol.owner, it.selector) @@ -1273,9 +1275,8 @@ private fun ObjCExportCodeGenerator.createTypeAdapter( if (type is ObjCClassForKotlinClass) { type.categoryMethods.forEach { - val irFunction = it.baseMethod.owner - adapters += createFinalMethodAdapter(irFunction) - reverseAdapters += nonOverridableAdapter(irFunction.descriptor, hasSelectorAmbiguity = false) + adapters += createFinalMethodAdapter(it.baseMethod) + reverseAdapters += nonOverridableAdapter(it.baseMethod.selector, hasSelectorAmbiguity = false) } adapters += createDirectAdapters(type, superClass) @@ -1283,9 +1284,11 @@ private fun ObjCExportCodeGenerator.createTypeAdapter( reverseAdapters += createReverseAdapters(type) - val virtualAdapters = type.kotlinMethods.map { it.baseMethod.owner } - .filter { it.parentAsClass == irClass && it.isOverridable } - .map { createMethodVirtualAdapter(it) } + val virtualAdapters = type.kotlinMethods + .filter { + val irFunction = it.baseMethod.symbol.owner + irFunction.parentAsClass == irClass && irFunction.isOverridable + }.map { createMethodVirtualAdapter(it.baseMethod) } val typeInfo = constPointer(codegen.typeInfoValue(irClass)) val objCName = type.binaryName @@ -1336,13 +1339,13 @@ private fun ObjCExportCodeGenerator.createReverseAdapters( type: ObjCTypeForKotlinType ): List { val result = mutableListOf() - val allBaseMethods = type.kotlinMethods.map { it.baseMethod.owner }.toSet() + val allBaseMethodsByIr = type.kotlinMethods.map { it.baseMethod }.associateBy { it.symbol.owner } for (method in type.irClassSymbol.owner.simpleFunctions()) { - val baseMethods = method.allOverriddenFunctions.filter { it in allBaseMethods } + val baseMethods = method.allOverriddenFunctions.mapNotNull { allBaseMethodsByIr[it] } if (baseMethods.isEmpty()) continue - val hasSelectorAmbiguity = baseMethods.map { namer.getSelector(it.descriptor) }.distinct().size > 1 + val hasSelectorAmbiguity = baseMethods.map { it.selector }.distinct().size > 1 if (method.isOverridable && !hasSelectorAmbiguity) { val baseMethod = baseMethods.first() @@ -1379,8 +1382,8 @@ private fun ObjCExportCodeGenerator.createReverseAdapters( } else { // Mark it as non-overridable: - baseMethods.distinctBy { namer.getSelector(it.descriptor) }.forEach { baseMethod -> - result += nonOverridableAdapter(baseMethod.descriptor, hasSelectorAmbiguity) + baseMethods.map { it.selector }.distinct().forEach { + result += nonOverridableAdapter(it, hasSelectorAmbiguity) } } } @@ -1389,10 +1392,10 @@ private fun ObjCExportCodeGenerator.createReverseAdapters( } private fun ObjCExportCodeGenerator.nonOverridableAdapter( - baseMethod: FunctionDescriptor, + selector: String, hasSelectorAmbiguity: Boolean ): ObjCExportCodeGenerator.KotlinToObjCMethodAdapter = KotlinToObjCMethodAdapter( - namer.getSelector(baseMethod), + selector, -1, vtableIndex = if (hasSelectorAmbiguity) -2 else -1, // Describes the reason. kotlinImpl = NullPointer(int8Type), @@ -1402,7 +1405,7 @@ private fun ObjCExportCodeGenerator.nonOverridableAdapter( private val ObjCTypeForKotlinType.kotlinMethods: List get() = this.methods.filterIsInstance() -internal data class DirectAdapterRequest(val implementation: IrFunction?, val base: IrFunction) +internal data class DirectAdapterRequest(val implementation: IrFunction?, val base: ObjCMethodSpec.BaseMethod<*>) private fun ObjCExportCodeGenerator.createDirectAdapters( typeDeclaration: ObjCClassForKotlinClass, @@ -1411,15 +1414,15 @@ private fun ObjCExportCodeGenerator.createDirectAdapters( fun ObjCClassForKotlinClass.getAllRequiredDirectAdapters() = this.kotlinMethods.map { method -> DirectAdapterRequest( - findImplementation(irClassSymbol.owner, method.baseMethod.owner, context), - method.baseMethod.owner + findImplementation(irClassSymbol.owner, method.baseMethod.symbol.owner, context), + method.baseMethod ) } val inheritedAdapters = superClass?.getAllRequiredDirectAdapters().orEmpty() val requiredAdapters = typeDeclaration.getAllRequiredDirectAdapters() - inheritedAdapters - return requiredAdapters.distinctBy { namer.getSelector(it.base.descriptor) }.map { createMethodAdapter(it) } + return requiredAdapters.distinctBy { it.base.selector }.map { createMethodAdapter(it) } } private fun findImplementation(irClass: IrClass, method: IrSimpleFunction, context: Context): IrSimpleFunction? { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportCodeSpec.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportCodeSpec.kt index 1f7134e545e..cd7da97f839 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportCodeSpec.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportCodeSpec.kt @@ -17,7 +17,14 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny internal fun ObjCExportedInterface.createCodeSpec(symbolTable: SymbolTable): ObjCExportCodeSpec { fun createObjCMethods(methods: List) = methods.map { - ObjCMethodForKotlinMethod(symbolTable.referenceSimpleFunction(it)) + ObjCMethodForKotlinMethod( + createObjCMethodSpecBaseMethod( + mapper, + namer, + symbolTable.referenceSimpleFunction(it), + it + ) + ) } fun List.toObjCMethods() = createObjCMethods(this.flatMap { @@ -55,11 +62,12 @@ internal fun ObjCExportedInterface.createCodeSpec(symbolTable: SymbolTable): Obj } else { descriptor.constructors.filter { mapper.shouldBeExposed(it) }.mapTo(methods) { val irConstructorSymbol = symbolTable.referenceConstructor(it) + val baseMethod = createObjCMethodSpecBaseMethod(mapper, namer, irConstructorSymbol, it) if (descriptor.isArray) { - ObjCFactoryMethodForKotlinArrayConstructor(irConstructorSymbol) + ObjCFactoryMethodForKotlinArrayConstructor(baseMethod) } else { - ObjCInitMethodForKotlinConstructor(irConstructorSymbol) + ObjCInitMethodForKotlinConstructor(baseMethod) } } @@ -94,19 +102,39 @@ internal fun ObjCExportedInterface.createCodeSpec(symbolTable: SymbolTable): Obj return ObjCExportCodeSpec(files, types) } +internal fun createObjCMethodSpecBaseMethod( + mapper: ObjCExportMapper, + namer: ObjCExportNamer, + symbol: S, + descriptor: FunctionDescriptor +): ObjCMethodSpec.BaseMethod { + require(mapper.isBaseMethod(descriptor)) + + val selector = namer.getSelector(descriptor) + val bridge = mapper.bridgeMethod(descriptor) + + return ObjCMethodSpec.BaseMethod(symbol, bridge, selector) +} + internal class ObjCExportCodeSpec( val files: List, val types: List ) -internal sealed class ObjCMethodSpec +internal sealed class ObjCMethodSpec { + /** + * Aggregates base method (as defined by [ObjCExportMapper.isBaseMethod]) + * and details required to generate code for bridges between Kotlin and Obj-C methods. + */ + data class BaseMethod(val symbol: S, val bridge: MethodBridge, val selector: String) +} -internal class ObjCMethodForKotlinMethod(val baseMethod: IrSimpleFunctionSymbol) : ObjCMethodSpec() +internal class ObjCMethodForKotlinMethod(val baseMethod: BaseMethod) : ObjCMethodSpec() -internal class ObjCInitMethodForKotlinConstructor(val irConstructorSymbol: IrConstructorSymbol) : ObjCMethodSpec() +internal class ObjCInitMethodForKotlinConstructor(val baseMethod: BaseMethod) : ObjCMethodSpec() internal class ObjCFactoryMethodForKotlinArrayConstructor( - val irConstructorSymbol: IrConstructorSymbol + val baseMethod: BaseMethod ) : ObjCMethodSpec() internal class ObjCGetterForKotlinEnumEntry(