Make ObjCExportCodeGenerator more explicit and decoupled
Also stop using SymbolTable
This commit is contained in:
committed by
SvyatoslavScherbina
parent
702322bd78
commit
0757bfb927
+3
-2
@@ -66,10 +66,11 @@ internal val createSymbolTablePhase = konanUnitPhase(
|
|||||||
|
|
||||||
internal val objCExportPhase = konanUnitPhase(
|
internal val objCExportPhase = konanUnitPhase(
|
||||||
op = {
|
op = {
|
||||||
objCExport = ObjCExport(this)
|
objCExport = ObjCExport(this, symbolTable!!)
|
||||||
},
|
},
|
||||||
name = "ObjCExport",
|
name = "ObjCExport",
|
||||||
description = "Objective-C header generation"
|
description = "Objective-C header generation",
|
||||||
|
prerequisite = setOf(createSymbolTablePhase)
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val buildCExportsPhase = konanUnitPhase(
|
internal val buildCExportsPhase = konanUnitPhase(
|
||||||
|
|||||||
+7
@@ -181,6 +181,13 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
|
|||||||
}
|
}
|
||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
|
val list = symbolTable.referenceClass(builtIns.list)
|
||||||
|
val mutableList = symbolTable.referenceClass(builtIns.mutableList)
|
||||||
|
val set = symbolTable.referenceClass(builtIns.set)
|
||||||
|
val mutableSet = symbolTable.referenceClass(builtIns.mutableSet)
|
||||||
|
val map = symbolTable.referenceClass(builtIns.map)
|
||||||
|
val mutableMap = symbolTable.referenceClass(builtIns.mutableMap)
|
||||||
|
|
||||||
val arrayList = symbolTable.referenceClass(getArrayListClassDescriptor(context))
|
val arrayList = symbolTable.referenceClass(getArrayListClassDescriptor(context))
|
||||||
|
|
||||||
val symbolName = topLevelClass(RuntimeNames.symbolName)
|
val symbolName = topLevelClass(RuntimeNames.symbolName)
|
||||||
|
|||||||
+233
-203
@@ -6,25 +6,25 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.llvm.objcexport
|
package org.jetbrains.kotlin.backend.konan.llvm.objcexport
|
||||||
|
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.common.atMostOne
|
|
||||||
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
|
||||||
import org.jetbrains.kotlin.backend.konan.*
|
import org.jetbrains.kotlin.backend.konan.*
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.backend.konan.ir.allParameters
|
||||||
|
import org.jetbrains.kotlin.backend.konan.ir.isOverridable
|
||||||
|
import org.jetbrains.kotlin.backend.konan.ir.isUnit
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCCodeGenerator
|
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCCodeGenerator
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCDataGenerator
|
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCDataGenerator
|
||||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin
|
import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
import org.jetbrains.kotlin.ir.util.isInterface
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
import org.jetbrains.kotlin.ir.util.simpleFunctions
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
internal fun TypeBridge.makeNothing() = when (this) {
|
internal fun TypeBridge.makeNothing() = when (this) {
|
||||||
@@ -38,6 +38,8 @@ internal class ObjCExportCodeGenerator(
|
|||||||
val mapper: ObjCExportMapper
|
val mapper: ObjCExportMapper
|
||||||
) : ObjCCodeGenerator(codegen) {
|
) : ObjCCodeGenerator(codegen) {
|
||||||
|
|
||||||
|
val symbols get() = context.ir.symbols
|
||||||
|
|
||||||
val runtime get() = codegen.runtime
|
val runtime get() = codegen.runtime
|
||||||
val staticData get() = codegen.staticData
|
val staticData get() = codegen.staticData
|
||||||
|
|
||||||
@@ -145,12 +147,12 @@ internal class ObjCExportCodeGenerator(
|
|||||||
|
|
||||||
inline fun FunctionGenerationContext.convertKotlin(
|
inline fun FunctionGenerationContext.convertKotlin(
|
||||||
genValue: (Lifetime) -> LLVMValueRef,
|
genValue: (Lifetime) -> LLVMValueRef,
|
||||||
actualType: KotlinType,
|
actualType: IrType,
|
||||||
expectedType: KotlinType,
|
expectedType: IrType,
|
||||||
resultLifetime: Lifetime
|
resultLifetime: Lifetime
|
||||||
): LLVMValueRef {
|
): LLVMValueRef {
|
||||||
|
|
||||||
val conversion = context.ir.symbols.getTypeConversion(actualType, expectedType)
|
val conversion = symbols.getTypeConversion(actualType, expectedType)
|
||||||
?: return genValue(resultLifetime)
|
?: return genValue(resultLifetime)
|
||||||
|
|
||||||
val value = genValue(Lifetime.ARGUMENT)
|
val value = genValue(Lifetime.ARGUMENT)
|
||||||
@@ -160,29 +162,26 @@ internal class ObjCExportCodeGenerator(
|
|||||||
|
|
||||||
private val objCTypeAdapters = mutableListOf<ObjCTypeAdapter>()
|
private val objCTypeAdapters = mutableListOf<ObjCTypeAdapter>()
|
||||||
|
|
||||||
internal fun generate(
|
internal fun generate(spec: ObjCExportCodeSpec) {
|
||||||
generatedClasses: Collection<ClassDescriptor>,
|
spec.types.forEach {
|
||||||
categoryMembers: Map<ClassDescriptor, List<CallableMemberDescriptor>>,
|
objCTypeAdapters += when (it) {
|
||||||
topLevel: Map<SourceFile, List<CallableMemberDescriptor>>
|
is ObjCClassForKotlinClass -> {
|
||||||
) {
|
val superClass = it.superClassNotAny ?: objCClassForAny
|
||||||
generatedClasses.forEach {
|
|
||||||
objCTypeAdapters += createTypeAdapter(it, categoryMembers[it].orEmpty())
|
|
||||||
|
|
||||||
if (!it.isInterface) {
|
dataGenerator.emitEmptyClass(it.binaryName, superClass.binaryName)
|
||||||
val className = namer.getClassOrProtocolName(it).binaryName
|
// Note: it is generated only to be visible for linker.
|
||||||
val superClass = it.getSuperClassOrAny()
|
// Methods will be added at runtime.
|
||||||
val superClassName = namer.getClassOrProtocolName(superClass).binaryName
|
|
||||||
|
|
||||||
dataGenerator.emitEmptyClass(className, superClassName)
|
createTypeAdapter(it, superClass)
|
||||||
// Note: it is generated only to be visible for linker.
|
}
|
||||||
// Methods will be added at runtime.
|
|
||||||
|
is ObjCProtocolForKotlinInterface -> createTypeAdapter(it, superClass = null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
topLevel.forEach { sourceFile, declarations ->
|
spec.files.forEach {
|
||||||
objCTypeAdapters += createTypeAdapterForFileClass(sourceFile, declarations)
|
objCTypeAdapters += createTypeAdapterForFileClass(it)
|
||||||
val name = namer.getFileClassName(sourceFile).binaryName
|
dataGenerator.emitEmptyClass(it.binaryName, namer.kotlinAnyName.binaryName)
|
||||||
dataGenerator.emitEmptyClass(name, namer.kotlinAnyName.binaryName)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,16 +194,16 @@ internal class ObjCExportCodeGenerator(
|
|||||||
|
|
||||||
emitSpecialClassesConvertions()
|
emitSpecialClassesConvertions()
|
||||||
|
|
||||||
objCTypeAdapters += createTypeAdapter(context.builtIns.any, categoryMembers = emptyList())
|
objCTypeAdapters += createTypeAdapter(objCClassForAny, superClass = null)
|
||||||
|
|
||||||
val placedClassAdapters = mutableMapOf<String, ConstPointer>()
|
val placedClassAdapters = mutableMapOf<String, ConstPointer>()
|
||||||
val placedInterfaceAdapters = mutableMapOf<String, ConstPointer>()
|
val placedInterfaceAdapters = mutableMapOf<String, ConstPointer>()
|
||||||
|
|
||||||
objCTypeAdapters.forEach { adapter ->
|
objCTypeAdapters.forEach { adapter ->
|
||||||
val typeAdapter = staticData.placeGlobal("", adapter).pointer
|
val typeAdapter = staticData.placeGlobal("", adapter).pointer
|
||||||
val descriptor = adapter.descriptor
|
val irClass = adapter.irClass
|
||||||
|
|
||||||
val descriptorToAdapter = if (descriptor?.isInterface == true) {
|
val descriptorToAdapter = if (irClass?.isInterface == true) {
|
||||||
placedInterfaceAdapters
|
placedInterfaceAdapters
|
||||||
} else {
|
} else {
|
||||||
// Objective-C class for Kotlin class or top-level declarations.
|
// Objective-C class for Kotlin class or top-level declarations.
|
||||||
@@ -212,8 +211,8 @@ internal class ObjCExportCodeGenerator(
|
|||||||
}
|
}
|
||||||
descriptorToAdapter[adapter.objCName] = typeAdapter
|
descriptorToAdapter[adapter.objCName] = typeAdapter
|
||||||
|
|
||||||
if (descriptor != null) {
|
if (irClass != null) {
|
||||||
setObjCExportTypeInfo(descriptor, typeAdapter = typeAdapter)
|
setObjCExportTypeInfo(irClass, typeAdapter = typeAdapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +236,20 @@ internal class ObjCExportCodeGenerator(
|
|||||||
emitSelectorsHolder()
|
emitSelectorsHolder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: consider including this into ObjCExportCodeSpec.
|
||||||
|
private val objCClassForAny = ObjCClassForKotlinClass(
|
||||||
|
namer.kotlinAnyName.binaryName,
|
||||||
|
symbols.any,
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
categoryMethods = emptyList(),
|
||||||
|
superClassNotAny = null
|
||||||
|
)
|
||||||
|
|
||||||
private fun emitSelectorsHolder() {
|
private fun emitSelectorsHolder() {
|
||||||
val impType = functionType(voidType, false, int8TypePtr, int8TypePtr)
|
val impType = functionType(voidType, false, int8TypePtr, int8TypePtr)
|
||||||
val imp = generateFunction(codegen, impType, "") {
|
val imp = generateFunction(codegen, impType, "") {
|
||||||
@@ -279,7 +292,7 @@ internal class ObjCExportCodeGenerator(
|
|||||||
)
|
)
|
||||||
|
|
||||||
inner class ObjCTypeAdapter(
|
inner class ObjCTypeAdapter(
|
||||||
val descriptor: ClassDescriptor?,
|
val irClass: IrClass?,
|
||||||
typeInfo: ConstPointer?,
|
typeInfo: ConstPointer?,
|
||||||
vtable: ConstPointer?,
|
vtable: ConstPointer?,
|
||||||
vtableSize: Int,
|
vtableSize: Int,
|
||||||
@@ -333,7 +346,7 @@ internal class ObjCExportCodeGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
|
private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
|
||||||
descriptor: ClassDescriptor,
|
irClass: IrClass,
|
||||||
converter: ConstPointer? = null,
|
converter: ConstPointer? = null,
|
||||||
objCClass: ConstPointer? = null,
|
objCClass: ConstPointer? = null,
|
||||||
typeAdapter: ConstPointer? = null
|
typeAdapter: ConstPointer? = null
|
||||||
@@ -351,7 +364,6 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
|
|||||||
val writableTypeInfoType = runtime.writableTypeInfoType!!
|
val writableTypeInfoType = runtime.writableTypeInfoType!!
|
||||||
val writableTypeInfoValue = Struct(writableTypeInfoType, objCExportAddition)
|
val writableTypeInfoValue = Struct(writableTypeInfoType, objCExportAddition)
|
||||||
|
|
||||||
val irClass = context.ir.get(descriptor)
|
|
||||||
val global = if (codegen.isExternal(irClass)) {
|
val global = if (codegen.isExternal(irClass)) {
|
||||||
// Note: this global replaces the external one with common linkage.
|
// Note: this global replaces the external one with common linkage.
|
||||||
staticData.createGlobal(
|
staticData.createGlobal(
|
||||||
@@ -373,7 +385,6 @@ private val ObjCExportCodeGenerator.kotlinToObjCFunctionType: LLVMTypeRef
|
|||||||
|
|
||||||
private fun ObjCExportCodeGenerator.emitBoxConverters() {
|
private fun ObjCExportCodeGenerator.emitBoxConverters() {
|
||||||
val irBuiltIns = context.irBuiltIns
|
val irBuiltIns = context.irBuiltIns
|
||||||
val symbols = context.ir.symbols
|
|
||||||
|
|
||||||
emitBoxConverter(irBuiltIns.booleanClass, ObjCValueType.BOOL, "numberWithBool:")
|
emitBoxConverter(irBuiltIns.booleanClass, ObjCValueType.BOOL, "numberWithBool:")
|
||||||
emitBoxConverter(irBuiltIns.byteClass, ObjCValueType.CHAR, "numberWithChar:")
|
emitBoxConverter(irBuiltIns.byteClass, ObjCValueType.CHAR, "numberWithChar:")
|
||||||
@@ -411,7 +422,7 @@ private fun ObjCExportCodeGenerator.emitBoxConverter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
LLVMSetLinkage(converter, LLVMLinkage.LLVMPrivateLinkage)
|
LLVMSetLinkage(converter, LLVMLinkage.LLVMPrivateLinkage)
|
||||||
setObjCExportTypeInfo(boxClass.descriptor, constPointer(converter))
|
setObjCExportTypeInfo(boxClass, constPointer(converter))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.emitFunctionConverters() {
|
private fun ObjCExportCodeGenerator.emitFunctionConverters() {
|
||||||
@@ -419,12 +430,12 @@ private fun ObjCExportCodeGenerator.emitFunctionConverters() {
|
|||||||
|
|
||||||
(0 .. ObjCExportMapper.maxFunctionTypeParameterCount).forEach { numberOfParameters ->
|
(0 .. ObjCExportMapper.maxFunctionTypeParameterCount).forEach { numberOfParameters ->
|
||||||
val converter = generator.run { generateConvertFunctionToBlock(numberOfParameters) }
|
val converter = generator.run { generateConvertFunctionToBlock(numberOfParameters) }
|
||||||
setObjCExportTypeInfo(context.builtIns.getFunction(numberOfParameters), constPointer(converter))
|
setObjCExportTypeInfo(symbols.functions[numberOfParameters].owner, constPointer(converter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.generateKotlinFunctionAdapterToBlock(numberOfParameters: Int): ConstPointer {
|
private fun ObjCExportCodeGenerator.generateKotlinFunctionAdapterToBlock(numberOfParameters: Int): ConstPointer {
|
||||||
val irInterface = context.ir.symbols.functions[numberOfParameters].owner
|
val irInterface = symbols.functions[numberOfParameters].owner
|
||||||
val invokeMethod = irInterface.declarations.filterIsInstance<IrSimpleFunction>()
|
val invokeMethod = irInterface.declarations.filterIsInstance<IrSimpleFunction>()
|
||||||
.single { it.name == OperatorNameConventions.INVOKE }
|
.single { it.name == OperatorNameConventions.INVOKE }
|
||||||
|
|
||||||
@@ -452,37 +463,37 @@ private fun ObjCExportCodeGenerator.emitKotlinFunctionAdaptersToBlock() {
|
|||||||
|
|
||||||
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
|
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
|
||||||
setObjCExportTypeInfo(
|
setObjCExportTypeInfo(
|
||||||
context.builtIns.string,
|
symbols.string.owner,
|
||||||
constPointer(context.llvm.Kotlin_ObjCExport_CreateNSStringFromKString)
|
constPointer(context.llvm.Kotlin_ObjCExport_CreateNSStringFromKString)
|
||||||
)
|
)
|
||||||
|
|
||||||
setObjCExportTypeInfo(
|
setObjCExportTypeInfo(
|
||||||
context.builtIns.list,
|
symbols.list.owner,
|
||||||
constPointer(context.llvm.Kotlin_Interop_CreateNSArrayFromKList)
|
constPointer(context.llvm.Kotlin_Interop_CreateNSArrayFromKList)
|
||||||
)
|
)
|
||||||
|
|
||||||
setObjCExportTypeInfo(
|
setObjCExportTypeInfo(
|
||||||
context.builtIns.mutableList,
|
symbols.mutableList.owner,
|
||||||
constPointer(context.llvm.Kotlin_Interop_CreateNSMutableArrayFromKList)
|
constPointer(context.llvm.Kotlin_Interop_CreateNSMutableArrayFromKList)
|
||||||
)
|
)
|
||||||
|
|
||||||
setObjCExportTypeInfo(
|
setObjCExportTypeInfo(
|
||||||
context.builtIns.set,
|
symbols.set.owner,
|
||||||
constPointer(context.llvm.Kotlin_Interop_CreateNSSetFromKSet)
|
constPointer(context.llvm.Kotlin_Interop_CreateNSSetFromKSet)
|
||||||
)
|
)
|
||||||
|
|
||||||
setObjCExportTypeInfo(
|
setObjCExportTypeInfo(
|
||||||
context.builtIns.mutableSet,
|
symbols.mutableSet.owner,
|
||||||
constPointer(context.llvm.Kotlin_Interop_CreateKotlinMutableSetFromKSet)
|
constPointer(context.llvm.Kotlin_Interop_CreateKotlinMutableSetFromKSet)
|
||||||
)
|
)
|
||||||
|
|
||||||
setObjCExportTypeInfo(
|
setObjCExportTypeInfo(
|
||||||
context.builtIns.map,
|
symbols.map.owner,
|
||||||
constPointer(context.llvm.Kotlin_Interop_CreateNSDictionaryFromKMap)
|
constPointer(context.llvm.Kotlin_Interop_CreateNSDictionaryFromKMap)
|
||||||
)
|
)
|
||||||
|
|
||||||
setObjCExportTypeInfo(
|
setObjCExportTypeInfo(
|
||||||
context.builtIns.mutableMap,
|
symbols.mutableMap.owner,
|
||||||
constPointer(context.llvm.Kotlin_Interop_CreateKotlinMutableDictonaryFromKMap)
|
constPointer(context.llvm.Kotlin_Interop_CreateKotlinMutableDictonaryFromKMap)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -585,7 +596,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
|
|||||||
// TODO: consider merging this handler with function cleanup.
|
// TODO: consider merging this handler with function cleanup.
|
||||||
val exceptionHandler = if (errorOutPtr == null) {
|
val exceptionHandler = if (errorOutPtr == null) {
|
||||||
kotlinExceptionHandler { exception ->
|
kotlinExceptionHandler { exception ->
|
||||||
callFromBridge(context.ir.symbols.objCExportTrapOnUndeclaredException.owner.llvmFunction, listOf(exception))
|
callFromBridge(symbols.objCExportTrapOnUndeclaredException.owner.llvmFunction, listOf(exception))
|
||||||
unreachable()
|
unreachable()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -640,44 +651,44 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.generateObjCImpForArrayConstructor(
|
private fun ObjCExportCodeGenerator.generateObjCImpForArrayConstructor(
|
||||||
target: ConstructorDescriptor,
|
target: IrConstructor,
|
||||||
methodBridge: MethodBridge
|
methodBridge: MethodBridge
|
||||||
): LLVMValueRef = generateObjCImp(methodBridge) { args, resultLifetime, exceptionHandler ->
|
): LLVMValueRef = generateObjCImp(methodBridge) { args, resultLifetime, exceptionHandler ->
|
||||||
val targetIr = context.ir.get(target)
|
|
||||||
|
|
||||||
val arrayInstance = callFromBridge(
|
val arrayInstance = callFromBridge(
|
||||||
context.llvm.allocArrayFunction,
|
context.llvm.allocArrayFunction,
|
||||||
listOf((targetIr as IrConstructor).constructedClass.llvmTypeInfoPtr, args.first()),
|
listOf(target.constructedClass.llvmTypeInfoPtr, args.first()),
|
||||||
resultLifetime = Lifetime.ARGUMENT
|
resultLifetime = Lifetime.ARGUMENT
|
||||||
)
|
)
|
||||||
|
|
||||||
call(targetIr.llvmFunction, listOf(arrayInstance) + args, resultLifetime, exceptionHandler)
|
call(target.llvmFunction, listOf(arrayInstance) + args, resultLifetime, exceptionHandler)
|
||||||
arrayInstance
|
arrayInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cache bridges.
|
// TODO: cache bridges.
|
||||||
private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
||||||
descriptor: FunctionDescriptor,
|
irFunction: IrFunction,
|
||||||
baseMethod: FunctionDescriptor
|
baseIrFunction: IrFunction
|
||||||
): ConstPointer {
|
): ConstPointer {
|
||||||
|
val baseMethod = baseIrFunction.descriptor
|
||||||
|
|
||||||
val methodBridge = mapper.bridgeMethod(baseMethod)
|
val methodBridge = mapper.bridgeMethod(baseMethod)
|
||||||
|
|
||||||
val parameterToBase = descriptor.allParameters.zip(baseMethod.allParameters).toMap()
|
val parameterToBase = irFunction.allParameters.zip(baseIrFunction.allParameters).toMap()
|
||||||
|
|
||||||
val objcMsgSend = msgSender(objCFunctionType(context, methodBridge))
|
val objcMsgSend = msgSender(objCFunctionType(context, methodBridge))
|
||||||
|
|
||||||
val functionType = codegen.getLlvmFunctionType(context.ir.get(descriptor))
|
val functionType = codegen.getLlvmFunctionType(irFunction)
|
||||||
|
|
||||||
val result = generateFunction(codegen, functionType, "") {
|
val result = generateFunction(codegen, functionType, "") {
|
||||||
var errorOutPtr: LLVMValueRef? = null
|
var errorOutPtr: LLVMValueRef? = null
|
||||||
var kotlinResultOutPtr: LLVMValueRef? = null
|
var kotlinResultOutPtr: LLVMValueRef? = null
|
||||||
lateinit var kotlinResultOutBridge: TypeBridge
|
lateinit var kotlinResultOutBridge: TypeBridge
|
||||||
|
|
||||||
val parameters = descriptor.allParameters.mapIndexed { index, parameterDescriptor ->
|
val parameters = irFunction.allParameters.mapIndexed { index, parameterDescriptor ->
|
||||||
parameterDescriptor to param(index)
|
parameterDescriptor to param(index)
|
||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
val objCArgs = methodBridge.parametersAssociated(descriptor).map { (bridge, parameter) ->
|
val objCArgs = methodBridge.parametersAssociated(irFunction).map { (bridge, parameter) ->
|
||||||
when (bridge) {
|
when (bridge) {
|
||||||
is MethodBridgeValueParameter.Mapped -> {
|
is MethodBridgeValueParameter.Mapped -> {
|
||||||
parameter!!
|
parameter!!
|
||||||
@@ -765,8 +776,8 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
|||||||
error("init or factory method can't have bridge for overriding: $baseMethod")
|
error("init or factory method can't have bridge for overriding: $baseMethod")
|
||||||
}
|
}
|
||||||
|
|
||||||
val baseReturnType = baseMethod.returnType!!
|
val baseReturnType = baseIrFunction.returnType
|
||||||
val actualReturnType = descriptor.returnType!!
|
val actualReturnType = irFunction.returnType
|
||||||
|
|
||||||
val retVal = when {
|
val retVal = when {
|
||||||
actualReturnType.isUnit() || actualReturnType.isNothing() -> {
|
actualReturnType.isUnit() || actualReturnType.isNothing() -> {
|
||||||
@@ -795,17 +806,17 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createReverseAdapter(
|
private fun ObjCExportCodeGenerator.createReverseAdapter(
|
||||||
descriptor: FunctionDescriptor,
|
irFunction: IrFunction,
|
||||||
baseMethod: FunctionDescriptor,
|
baseMethod: IrFunction,
|
||||||
functionName: String,
|
functionName: String,
|
||||||
vtableIndex: Int?
|
vtableIndex: Int?
|
||||||
): ObjCExportCodeGenerator.KotlinToObjCMethodAdapter {
|
): ObjCExportCodeGenerator.KotlinToObjCMethodAdapter {
|
||||||
|
|
||||||
val nameSignature = functionName.localHash.value
|
val nameSignature = functionName.localHash.value
|
||||||
val selector = namer.getSelector(baseMethod)
|
val selector = namer.getSelector(baseMethod.descriptor)
|
||||||
|
|
||||||
val kotlinToObjC = generateKotlinToObjCBridge(
|
val kotlinToObjC = generateKotlinToObjCBridge(
|
||||||
descriptor,
|
irFunction,
|
||||||
baseMethod
|
baseMethod
|
||||||
).bitcast(int8TypePtr)
|
).bitcast(int8TypePtr)
|
||||||
|
|
||||||
@@ -813,28 +824,35 @@ private fun ObjCExportCodeGenerator.createReverseAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createMethodVirtualAdapter(
|
private fun ObjCExportCodeGenerator.createMethodVirtualAdapter(
|
||||||
baseMethod: FunctionDescriptor
|
baseMethod: IrFunction
|
||||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||||
assert(mapper.isBaseMethod(baseMethod))
|
assert(mapper.isBaseMethod(baseMethod.descriptor))
|
||||||
|
|
||||||
val selector = namer.getSelector(baseMethod)
|
val selector = namer.getSelector(baseMethod.descriptor)
|
||||||
|
|
||||||
val methodBridge = mapper.bridgeMethod(baseMethod)
|
val methodBridge = mapper.bridgeMethod(baseMethod.descriptor)
|
||||||
val objCToKotlin = constPointer(generateObjCImp(context.ir.get(baseMethod), methodBridge, isVirtual = true))
|
val objCToKotlin = constPointer(generateObjCImp(baseMethod, methodBridge, isVirtual = true))
|
||||||
return ObjCToKotlinMethodAdapter(selector, getEncoding(methodBridge), objCToKotlin)
|
return ObjCToKotlinMethodAdapter(selector, getEncoding(methodBridge), objCToKotlin)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createMethodAdapter(
|
private fun ObjCExportCodeGenerator.createMethodAdapter(
|
||||||
implementation: FunctionDescriptor?,
|
implementation: IrFunction?,
|
||||||
baseMethod: FunctionDescriptor
|
baseMethod: IrFunction
|
||||||
) = createMethodAdapter(DirectAdapterRequest(implementation?.let { context.ir.get(it) }, baseMethod))
|
) = createMethodAdapter(DirectAdapterRequest(implementation, baseMethod))
|
||||||
|
|
||||||
|
private fun ObjCExportCodeGenerator.createFinalMethodAdapter(
|
||||||
|
irFunction: IrSimpleFunction
|
||||||
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||||
|
require(irFunction.modality == Modality.FINAL)
|
||||||
|
return createMethodAdapter(irFunction, irFunction)
|
||||||
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createMethodAdapter(
|
private fun ObjCExportCodeGenerator.createMethodAdapter(
|
||||||
request: DirectAdapterRequest
|
request: DirectAdapterRequest
|
||||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter = this.directMethodAdapters.getOrPut(request) {
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter = this.directMethodAdapters.getOrPut(request) {
|
||||||
|
|
||||||
val selectorName = namer.getSelector(request.base)
|
val selectorName = namer.getSelector(request.base.descriptor)
|
||||||
val methodBridge = mapper.bridgeMethod(request.base)
|
val methodBridge = mapper.bridgeMethod(request.base.descriptor)
|
||||||
val objCEncoding = getEncoding(methodBridge)
|
val objCEncoding = getEncoding(methodBridge)
|
||||||
val objCToKotlin = constPointer(generateObjCImp(request.implementation, methodBridge))
|
val objCToKotlin = constPointer(generateObjCImp(request.implementation, methodBridge))
|
||||||
|
|
||||||
@@ -842,41 +860,39 @@ private fun ObjCExportCodeGenerator.createMethodAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createConstructorAdapter(
|
private fun ObjCExportCodeGenerator.createConstructorAdapter(
|
||||||
descriptor: ConstructorDescriptor
|
irConstructor: IrConstructor
|
||||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter = createMethodAdapter(descriptor, descriptor)
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter = createMethodAdapter(irConstructor, irConstructor)
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createArrayConstructorAdapter(
|
private fun ObjCExportCodeGenerator.createArrayConstructorAdapter(
|
||||||
descriptor: ConstructorDescriptor
|
irConstructor: IrConstructor
|
||||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||||
val selectorName = namer.getSelector(descriptor)
|
val selectorName = namer.getSelector(irConstructor.descriptor)
|
||||||
val methodBridge = mapper.bridgeMethod(descriptor)
|
val methodBridge = mapper.bridgeMethod(irConstructor.descriptor)
|
||||||
val objCEncoding = getEncoding(methodBridge)
|
val objCEncoding = getEncoding(methodBridge)
|
||||||
val objCToKotlin = constPointer(generateObjCImpForArrayConstructor(descriptor, methodBridge))
|
val objCToKotlin = constPointer(generateObjCImpForArrayConstructor(irConstructor, methodBridge))
|
||||||
|
|
||||||
return ObjCToKotlinMethodAdapter(selectorName, objCEncoding, objCToKotlin)
|
return ObjCToKotlinMethodAdapter(selectorName, objCEncoding, objCToKotlin)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.vtableIndex(descriptor: FunctionDescriptor): Int? {
|
private fun ObjCExportCodeGenerator.vtableIndex(irFunction: IrSimpleFunction): Int? {
|
||||||
assert(descriptor.isOverridable)
|
assert(irFunction.isOverridable)
|
||||||
val classDescriptor = descriptor.containingDeclaration as ClassDescriptor
|
val irClass = irFunction.parentAsClass
|
||||||
return if (classDescriptor.isInterface) {
|
return if (irClass.isInterface) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
context.getVtableBuilder(context.ir.get(classDescriptor))
|
context.getVtableBuilder(irClass).vtableIndex(irFunction)
|
||||||
.vtableIndex(context.ir.get(descriptor) as IrSimpleFunction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createTypeAdapterForFileClass(
|
private fun ObjCExportCodeGenerator.createTypeAdapterForFileClass(
|
||||||
sourceFile: SourceFile,
|
fileClass: ObjCClassForKotlinFile
|
||||||
declarations: List<CallableMemberDescriptor>
|
|
||||||
): ObjCExportCodeGenerator.ObjCTypeAdapter {
|
): ObjCExportCodeGenerator.ObjCTypeAdapter {
|
||||||
val name = namer.getFileClassName(sourceFile).binaryName
|
val name = fileClass.binaryName
|
||||||
|
|
||||||
val adapters = declarations.toMethods().map { createMethodAdapter(it, it) }
|
val adapters = fileClass.methods.map { createFinalMethodAdapter(it.baseMethod.owner) }
|
||||||
|
|
||||||
return ObjCTypeAdapter(
|
return ObjCTypeAdapter(
|
||||||
descriptor = null,
|
irClass = null,
|
||||||
typeInfo = null,
|
typeInfo = null,
|
||||||
vtable = null,
|
vtable = null,
|
||||||
vtableSize = -1,
|
vtableSize = -1,
|
||||||
@@ -890,96 +906,57 @@ private fun ObjCExportCodeGenerator.createTypeAdapterForFileClass(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createTypeAdapter(
|
private fun ObjCExportCodeGenerator.createTypeAdapter(
|
||||||
descriptor: ClassDescriptor,
|
type: ObjCTypeForKotlinType,
|
||||||
categoryMembers: List<CallableMemberDescriptor>
|
superClass: ObjCClassForKotlinClass?
|
||||||
): ObjCExportCodeGenerator.ObjCTypeAdapter {
|
): ObjCExportCodeGenerator.ObjCTypeAdapter {
|
||||||
|
val irClass = type.irClassSymbol.owner
|
||||||
val adapters = mutableListOf<ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter>()
|
val adapters = mutableListOf<ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter>()
|
||||||
val classAdapters = mutableListOf<ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter>()
|
val classAdapters = mutableListOf<ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter>()
|
||||||
|
|
||||||
if (descriptor != context.builtIns.any) {
|
type.methods.forEach {
|
||||||
descriptor.constructors.forEach {
|
when (it) {
|
||||||
if (mapper.shouldBeExposed(it)) {
|
is ObjCInitMethodForKotlinConstructor -> {
|
||||||
if (it.constructedClass.isArray) {
|
adapters += createConstructorAdapter(it.irConstructorSymbol.owner)
|
||||||
classAdapters += createArrayConstructorAdapter(it)
|
|
||||||
} else {
|
|
||||||
adapters += createConstructorAdapter(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
is ObjCFactoryMethodForKotlinArrayConstructor -> {
|
||||||
}
|
classAdapters += createArrayConstructorAdapter(it.irConstructorSymbol.owner)
|
||||||
|
}
|
||||||
val categoryMethods = categoryMembers.toMethods()
|
is ObjCGetterForKotlinEnumEntry -> {
|
||||||
|
classAdapters += createEnumEntryAdapter(it.irEnumEntrySymbol.owner)
|
||||||
val exposedMethods = descriptor.contributedMethods.filter { mapper.shouldBeExposed(it) } + categoryMethods
|
}
|
||||||
|
is ObjCMethodForKotlinMethod -> {} // Handled below.
|
||||||
exposedMethods.forEach {
|
}.let {} // Force exhaustive.
|
||||||
adapters += createDirectAdapters(it)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val reverseAdapters = mutableListOf<ObjCExportCodeGenerator.KotlinToObjCMethodAdapter>()
|
val reverseAdapters = mutableListOf<ObjCExportCodeGenerator.KotlinToObjCMethodAdapter>()
|
||||||
|
|
||||||
exposedMethods.forEach { method ->
|
if (type is ObjCClassForKotlinClass) {
|
||||||
val baseMethods = mapper.getBaseMethods(method)
|
|
||||||
val hasSelectorAmbiguity = baseMethods.map { namer.getSelector(it) }.distinct().size > 1
|
|
||||||
|
|
||||||
if (method.isOverridable && !hasSelectorAmbiguity) {
|
type.categoryMethods.forEach {
|
||||||
val baseMethod = baseMethods.first()
|
val irFunction = it.baseMethod.owner
|
||||||
|
adapters += createFinalMethodAdapter(irFunction)
|
||||||
val presentVtableBridges = mutableSetOf<Int?>(null)
|
reverseAdapters += nonOverridableAdapter(irFunction.descriptor, hasSelectorAmbiguity = false)
|
||||||
val presentMethodTableBridges = mutableSetOf<String>()
|
|
||||||
|
|
||||||
val allOverriddenDescriptors = method.allOverriddenDescriptors.map { it.original }
|
|
||||||
|
|
||||||
val (inherited, uninherited) = allOverriddenDescriptors.partition {
|
|
||||||
it != method && mapper.shouldBeExposed(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
inherited.forEach {
|
|
||||||
presentVtableBridges += vtableIndex(it)
|
|
||||||
presentMethodTableBridges += context.ir.get(it).functionName
|
|
||||||
}
|
|
||||||
|
|
||||||
uninherited.forEach {
|
|
||||||
val vtableIndex = vtableIndex(it)
|
|
||||||
val functionName = context.ir.get(it).functionName
|
|
||||||
|
|
||||||
if (vtableIndex !in presentVtableBridges || functionName !in presentMethodTableBridges) {
|
|
||||||
presentVtableBridges += vtableIndex
|
|
||||||
presentMethodTableBridges += functionName
|
|
||||||
reverseAdapters += createReverseAdapter(it, baseMethod, functionName, vtableIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Mark it as non-overridable:
|
|
||||||
baseMethods.distinctBy { namer.getSelector(it) }.forEach { baseMethod ->
|
|
||||||
reverseAdapters += KotlinToObjCMethodAdapter(
|
|
||||||
namer.getSelector(baseMethod),
|
|
||||||
-1,
|
|
||||||
vtableIndex = if (hasSelectorAmbiguity) -2 else -1, // Describes the reason.
|
|
||||||
kotlinImpl = NullPointer(int8Type)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: some fake-overrides can be skipped.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adapters += createDirectAdapters(type, superClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
val virtualAdapters = exposedMethods
|
reverseAdapters += createReverseAdapters(type)
|
||||||
.filter { mapper.isBaseMethod(it) && it.isOverridable }
|
|
||||||
|
val virtualAdapters = type.kotlinMethods.map { it.baseMethod.owner }
|
||||||
|
.filter { it.parentAsClass == irClass && it.isOverridable }
|
||||||
.map { createMethodVirtualAdapter(it) }
|
.map { createMethodVirtualAdapter(it) }
|
||||||
|
|
||||||
val irClass = context.ir.get(descriptor)
|
|
||||||
val typeInfo = constPointer(codegen.typeInfoValue(irClass))
|
val typeInfo = constPointer(codegen.typeInfoValue(irClass))
|
||||||
val objCName = namer.getClassOrProtocolName(descriptor).binaryName
|
val objCName = type.binaryName
|
||||||
|
|
||||||
val vtableSize = if (descriptor.kind == ClassKind.INTERFACE) {
|
val vtableSize = if (irClass.kind == ClassKind.INTERFACE) {
|
||||||
-1
|
-1
|
||||||
} else {
|
} else {
|
||||||
context.getVtableBuilder(irClass).vtableEntries.size
|
context.getVtableBuilder(irClass).vtableEntries.size
|
||||||
}
|
}
|
||||||
|
|
||||||
val vtable = if (!descriptor.isInterface && !irClass.typeInfoHasVtableAttached) {
|
val vtable = if (!irClass.isInterface && !irClass.typeInfoHasVtableAttached) {
|
||||||
staticData.placeGlobal("", rttiGenerator.vtable(irClass)).also {
|
staticData.placeGlobal("", rttiGenerator.vtable(irClass)).also {
|
||||||
it.setConstant(true)
|
it.setConstant(true)
|
||||||
}.pointer.getElementPtr(0)
|
}.pointer.getElementPtr(0)
|
||||||
@@ -987,23 +964,18 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
val methodTable = if (!descriptor.isInterface && descriptor.isAbstract()) {
|
val methodTable = if (!irClass.isInterface && irClass.isAbstract()) {
|
||||||
rttiGenerator.methodTableRecords(irClass)
|
rttiGenerator.methodTableRecords(irClass)
|
||||||
} else {
|
} else {
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
when (descriptor.kind) {
|
when (irClass.kind) {
|
||||||
ClassKind.OBJECT -> {
|
ClassKind.OBJECT -> {
|
||||||
classAdapters += if (descriptor.isUnit()) {
|
classAdapters += if (irClass.isUnit()) {
|
||||||
createUnitInstanceAdapter()
|
createUnitInstanceAdapter()
|
||||||
} else {
|
} else {
|
||||||
createObjectInstanceAdapter(descriptor)
|
createObjectInstanceAdapter(irClass)
|
||||||
}
|
|
||||||
}
|
|
||||||
ClassKind.ENUM_CLASS -> {
|
|
||||||
descriptor.enumEntries.mapTo(classAdapters) {
|
|
||||||
createEnumEntryAdapter(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@@ -1012,7 +984,7 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ObjCTypeAdapter(
|
return ObjCTypeAdapter(
|
||||||
descriptor,
|
irClass,
|
||||||
typeInfo,
|
typeInfo,
|
||||||
vtable,
|
vtable,
|
||||||
vtableSize,
|
vtableSize,
|
||||||
@@ -1025,35 +997,95 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal data class DirectAdapterRequest(val implementation: IrFunction?, val base: FunctionDescriptor)
|
private fun ObjCExportCodeGenerator.createReverseAdapters(
|
||||||
|
type: ObjCTypeForKotlinType
|
||||||
|
): List<ObjCExportCodeGenerator.KotlinToObjCMethodAdapter> {
|
||||||
|
val result = mutableListOf<ObjCExportCodeGenerator.KotlinToObjCMethodAdapter>()
|
||||||
|
val allBaseMethods = type.kotlinMethods.map { it.baseMethod.owner }.toSet()
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createDirectAdapters(
|
for (method in type.irClassSymbol.owner.simpleFunctions()) {
|
||||||
method: FunctionDescriptor
|
val baseMethods = method.allOverriddenFunctions.filter { it in allBaseMethods }
|
||||||
): List<ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter> {
|
if (baseMethods.isEmpty()) continue
|
||||||
|
|
||||||
|
val hasSelectorAmbiguity = baseMethods.map { namer.getSelector(it.descriptor) }.distinct().size > 1
|
||||||
|
|
||||||
|
if (method.isOverridable && !hasSelectorAmbiguity) {
|
||||||
|
val baseMethod = baseMethods.first()
|
||||||
|
|
||||||
|
val presentVtableBridges = mutableSetOf<Int?>(null)
|
||||||
|
val presentMethodTableBridges = mutableSetOf<String>()
|
||||||
|
|
||||||
|
val allOverriddenMethods = method.allOverriddenFunctions
|
||||||
|
|
||||||
|
val (inherited, uninherited) = allOverriddenMethods.partition {
|
||||||
|
it != method && mapper.shouldBeExposed(it.descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
inherited.forEach {
|
||||||
|
presentVtableBridges += vtableIndex(it)
|
||||||
|
presentMethodTableBridges += it.functionName
|
||||||
|
}
|
||||||
|
|
||||||
|
uninherited.forEach {
|
||||||
|
val vtableIndex = vtableIndex(it)
|
||||||
|
val functionName = it.functionName
|
||||||
|
|
||||||
|
if (vtableIndex !in presentVtableBridges || functionName !in presentMethodTableBridges) {
|
||||||
|
presentVtableBridges += vtableIndex
|
||||||
|
presentMethodTableBridges += functionName
|
||||||
|
result += createReverseAdapter(it, baseMethod, functionName, vtableIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun FunctionDescriptor.getAllRequiredDirectAdapters() = mapper.getBaseMethods(this).map { base ->
|
|
||||||
val implementation = if (this.modality == Modality.ABSTRACT) {
|
|
||||||
null
|
|
||||||
} else {
|
} else {
|
||||||
OverriddenFunctionInfo(
|
// Mark it as non-overridable:
|
||||||
context.ir.get(this) as IrSimpleFunction,
|
baseMethods.distinctBy { namer.getSelector(it.descriptor) }.forEach { baseMethod ->
|
||||||
context.ir.get(base) as IrSimpleFunction
|
result += nonOverridableAdapter(baseMethod.descriptor, hasSelectorAmbiguity)
|
||||||
).getImplementation(context)
|
}
|
||||||
}
|
}
|
||||||
DirectAdapterRequest(implementation, base)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val superClassMethod = method.overriddenDescriptors
|
return result
|
||||||
.atMostOne { !(it.containingDeclaration as ClassDescriptor).isInterface }?.original
|
}
|
||||||
|
|
||||||
val inheritedAdapters = superClassMethod?.getAllRequiredDirectAdapters().orEmpty()
|
private fun ObjCExportCodeGenerator.nonOverridableAdapter(
|
||||||
val requiredAdapters = method.getAllRequiredDirectAdapters()
|
baseMethod: FunctionDescriptor,
|
||||||
|
hasSelectorAmbiguity: Boolean
|
||||||
|
): ObjCExportCodeGenerator.KotlinToObjCMethodAdapter = KotlinToObjCMethodAdapter(
|
||||||
|
namer.getSelector(baseMethod),
|
||||||
|
-1,
|
||||||
|
vtableIndex = if (hasSelectorAmbiguity) -2 else -1, // Describes the reason.
|
||||||
|
kotlinImpl = NullPointer(int8Type)
|
||||||
|
)
|
||||||
|
|
||||||
return (requiredAdapters - inheritedAdapters)
|
private val ObjCTypeForKotlinType.kotlinMethods: List<ObjCMethodForKotlinMethod>
|
||||||
.distinctBy { namer.getSelector(it.base) }
|
get() = this.methods.filterIsInstance<ObjCMethodForKotlinMethod>()
|
||||||
.map {
|
|
||||||
createMethodAdapter(it)
|
internal data class DirectAdapterRequest(val implementation: IrFunction?, val base: IrFunction)
|
||||||
}
|
|
||||||
|
private fun ObjCExportCodeGenerator.createDirectAdapters(
|
||||||
|
typeDeclaration: ObjCClassForKotlinClass,
|
||||||
|
superClass: ObjCClassForKotlinClass?
|
||||||
|
): List<ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter> {
|
||||||
|
|
||||||
|
fun ObjCClassForKotlinClass.getAllRequiredDirectAdapters() = this.kotlinMethods.map { method ->
|
||||||
|
DirectAdapterRequest(
|
||||||
|
findImplementation(irClassSymbol.owner, method.baseMethod.owner, context),
|
||||||
|
method.baseMethod.owner
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val inheritedAdapters = superClass?.getAllRequiredDirectAdapters().orEmpty()
|
||||||
|
val requiredAdapters = typeDeclaration.getAllRequiredDirectAdapters() - inheritedAdapters
|
||||||
|
|
||||||
|
return requiredAdapters.distinctBy { namer.getSelector(it.base.descriptor) }.map { createMethodAdapter(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findImplementation(irClass: IrClass, method: IrSimpleFunction, context: Context): IrSimpleFunction? {
|
||||||
|
val override = irClass.simpleFunctions().singleOrNull {
|
||||||
|
method in it.allOverriddenFunctions
|
||||||
|
} ?: error("no implementation for ${method.descriptor}\nin ${irClass.descriptor}")
|
||||||
|
return OverriddenFunctionInfo(override, method).getImplementation(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
|
private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
|
||||||
@@ -1086,31 +1118,29 @@ private fun ObjCExportCodeGenerator.createUnitInstanceAdapter() =
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createObjectInstanceAdapter(
|
private fun ObjCExportCodeGenerator.createObjectInstanceAdapter(
|
||||||
descriptor: ClassDescriptor
|
irClass: IrClass
|
||||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||||
assert(descriptor.kind == ClassKind.OBJECT)
|
assert(irClass.kind == ClassKind.OBJECT)
|
||||||
assert(!descriptor.isUnit())
|
assert(!irClass.isUnit())
|
||||||
|
|
||||||
val selector = namer.getObjectInstanceSelector(descriptor)
|
val selector = namer.getObjectInstanceSelector(irClass.descriptor)
|
||||||
|
|
||||||
return generateObjCToKotlinSyntheticGetter(selector) {
|
return generateObjCToKotlinSyntheticGetter(selector) {
|
||||||
initRuntimeIfNeeded() // For instance methods it gets called when allocating.
|
initRuntimeIfNeeded() // For instance methods it gets called when allocating.
|
||||||
val value = getObjectValue(context.ir.get(descriptor), locationInfo = null, exceptionHandler = ExceptionHandler.Caller)
|
val value = getObjectValue(irClass, locationInfo = null, exceptionHandler = ExceptionHandler.Caller)
|
||||||
ret(kotlinToObjC(value, ReferenceBridge))
|
ret(kotlinToObjC(value, ReferenceBridge))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createEnumEntryAdapter(
|
private fun ObjCExportCodeGenerator.createEnumEntryAdapter(
|
||||||
descriptor: ClassDescriptor
|
irEnumEntry: IrEnumEntry
|
||||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||||
assert(descriptor.kind == ClassKind.ENUM_ENTRY)
|
val selector = namer.getEnumEntrySelector(irEnumEntry.descriptor)
|
||||||
|
|
||||||
val selector = namer.getEnumEntrySelector(descriptor)
|
|
||||||
|
|
||||||
return generateObjCToKotlinSyntheticGetter(selector) {
|
return generateObjCToKotlinSyntheticGetter(selector) {
|
||||||
initRuntimeIfNeeded() // For instance methods it gets called when allocating.
|
initRuntimeIfNeeded() // For instance methods it gets called when allocating.
|
||||||
|
|
||||||
val value = getEnumEntry(context.ir.getEnumEntry(descriptor), ExceptionHandler.Caller)
|
val value = getEnumEntry(irEnumEntry, ExceptionHandler.Caller)
|
||||||
ret(kotlinToObjC(value, ReferenceBridge))
|
ret(kotlinToObjC(value, ReferenceBridge))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -6,8 +6,11 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
||||||
|
import org.jetbrains.kotlin.backend.konan.ir.allParameters
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||||
|
|
||||||
internal sealed class TypeBridge
|
internal sealed class TypeBridge
|
||||||
internal object ReferenceBridge : TypeBridge()
|
internal object ReferenceBridge : TypeBridge()
|
||||||
@@ -85,9 +88,9 @@ internal fun MethodBridge.valueParametersAssociated(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun MethodBridge.parametersAssociated(
|
internal fun MethodBridge.parametersAssociated(
|
||||||
descriptor: FunctionDescriptor
|
irFunction: IrFunction
|
||||||
): List<Pair<MethodBridgeParameter, ParameterDescriptor?>> {
|
): List<Pair<MethodBridgeParameter, IrValueParameter?>> {
|
||||||
val kotlinParameters = descriptor.allParameters.iterator()
|
val kotlinParameters = irFunction.allParameters.iterator()
|
||||||
|
|
||||||
return this.paramBridges.map {
|
return this.paramBridges.map {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
|||||||
+4
-6
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.SourceFile
|
import org.jetbrains.kotlin.descriptors.SourceFile
|
||||||
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
import org.jetbrains.kotlin.konan.exec.Command
|
import org.jetbrains.kotlin.konan.exec.Command
|
||||||
import org.jetbrains.kotlin.konan.file.File
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
import org.jetbrains.kotlin.konan.file.createTempFile
|
import org.jetbrains.kotlin.konan.file.createTempFile
|
||||||
@@ -36,10 +37,11 @@ internal class ObjCExportedInterface(
|
|||||||
val mapper: ObjCExportMapper
|
val mapper: ObjCExportMapper
|
||||||
)
|
)
|
||||||
|
|
||||||
internal class ObjCExport(val context: Context) {
|
internal class ObjCExport(val context: Context, symbolTable: SymbolTable) {
|
||||||
private val target get() = context.config.target
|
private val target get() = context.config.target
|
||||||
|
|
||||||
private val exportedInterface = produceInterface()
|
private val exportedInterface = produceInterface()
|
||||||
|
private val codeSpec = exportedInterface?.createCodeSpec(symbolTable)
|
||||||
|
|
||||||
private fun produceInterface(): ObjCExportedInterface? {
|
private fun produceInterface(): ObjCExportedInterface? {
|
||||||
if (target.family != Family.IOS && target.family != Family.OSX) return null
|
if (target.family != Family.IOS && target.family != Family.OSX) return null
|
||||||
@@ -85,11 +87,7 @@ internal class ObjCExport(val context: Context) {
|
|||||||
if (exportedInterface != null) {
|
if (exportedInterface != null) {
|
||||||
produceFrameworkSpecific(exportedInterface.headerLines)
|
produceFrameworkSpecific(exportedInterface.headerLines)
|
||||||
|
|
||||||
objCCodeGenerator.generate(
|
objCCodeGenerator.generate(codeSpec!!)
|
||||||
generatedClasses = exportedInterface.generatedClasses,
|
|
||||||
categoryMembers = exportedInterface.categoryMembers,
|
|
||||||
topLevel = exportedInterface.topLevel
|
|
||||||
)
|
|
||||||
|
|
||||||
exportedInterface.generateWorkaroundForSwiftSR10177()
|
exportedInterface.generateWorkaroundForSwiftSR10177()
|
||||||
}
|
}
|
||||||
|
|||||||
+128
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.konan.descriptors.contributedMethods
|
||||||
|
import org.jetbrains.kotlin.backend.konan.descriptors.enumEntries
|
||||||
|
import org.jetbrains.kotlin.backend.konan.descriptors.isArray
|
||||||
|
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||||
|
|
||||||
|
internal fun ObjCExportedInterface.createCodeSpec(symbolTable: SymbolTable): ObjCExportCodeSpec {
|
||||||
|
|
||||||
|
fun createObjCMethods(methods: List<FunctionDescriptor>) = methods.map {
|
||||||
|
ObjCMethodForKotlinMethod(symbolTable.referenceSimpleFunction(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<CallableMemberDescriptor>.toObjCMethods() = createObjCMethods(this.flatMap {
|
||||||
|
when (it) {
|
||||||
|
is PropertyDescriptor -> listOfNotNull(it.getter, it.setter)
|
||||||
|
is FunctionDescriptor -> listOf(it)
|
||||||
|
else -> error(it)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
val files = topLevel.map { (sourceFile, declarations) ->
|
||||||
|
val binaryName = namer.getFileClassName(sourceFile).binaryName
|
||||||
|
val methods = declarations.toObjCMethods()
|
||||||
|
ObjCClassForKotlinFile(binaryName, methods)
|
||||||
|
}
|
||||||
|
|
||||||
|
val classToType = mutableMapOf<ClassDescriptor, ObjCTypeForKotlinType>()
|
||||||
|
fun getType(descriptor: ClassDescriptor): ObjCTypeForKotlinType = classToType.getOrPut(descriptor) {
|
||||||
|
val methods = mutableListOf<ObjCMethodSpec>()
|
||||||
|
|
||||||
|
// Note: contributedMethods includes fake overrides too.
|
||||||
|
val allBaseMethods = descriptor.contributedMethods.filter { mapper.shouldBeExposed(it) }
|
||||||
|
.flatMap { mapper.getBaseMethods(it) }.distinct()
|
||||||
|
|
||||||
|
methods += createObjCMethods(allBaseMethods)
|
||||||
|
|
||||||
|
val binaryName = namer.getClassOrProtocolName(descriptor).binaryName
|
||||||
|
val irClassSymbol = symbolTable.referenceClass(descriptor)
|
||||||
|
|
||||||
|
if (descriptor.isInterface) {
|
||||||
|
ObjCProtocolForKotlinInterface(binaryName, irClassSymbol, methods)
|
||||||
|
} else {
|
||||||
|
descriptor.constructors.filter { mapper.shouldBeExposed(it) }.mapTo(methods) {
|
||||||
|
val irConstructorSymbol = symbolTable.referenceConstructor(it)
|
||||||
|
|
||||||
|
if (descriptor.isArray) {
|
||||||
|
ObjCFactoryMethodForKotlinArrayConstructor(irConstructorSymbol)
|
||||||
|
} else {
|
||||||
|
ObjCInitMethodForKotlinConstructor(irConstructorSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor.kind == ClassKind.ENUM_ENTRY) {
|
||||||
|
descriptor.enumEntries.mapTo(methods) {
|
||||||
|
ObjCGetterForKotlinEnumEntry(symbolTable.referenceEnumEntry(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val categoryMethods = categoryMembers[descriptor].orEmpty().toObjCMethods()
|
||||||
|
|
||||||
|
val superClassNotAny = descriptor.getSuperClassNotAny()
|
||||||
|
?.let { getType(it) as ObjCClassForKotlinClass }
|
||||||
|
|
||||||
|
ObjCClassForKotlinClass(binaryName, irClassSymbol, methods, categoryMethods, superClassNotAny)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val types = generatedClasses.map { getType(it) }
|
||||||
|
|
||||||
|
return ObjCExportCodeSpec(files, types)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ObjCExportCodeSpec(
|
||||||
|
val files: List<ObjCClassForKotlinFile>,
|
||||||
|
val types: List<ObjCTypeForKotlinType>
|
||||||
|
)
|
||||||
|
|
||||||
|
internal sealed class ObjCMethodSpec
|
||||||
|
|
||||||
|
internal class ObjCMethodForKotlinMethod(val baseMethod: IrSimpleFunctionSymbol) : ObjCMethodSpec()
|
||||||
|
|
||||||
|
internal class ObjCInitMethodForKotlinConstructor(val irConstructorSymbol: IrConstructorSymbol) : ObjCMethodSpec()
|
||||||
|
|
||||||
|
internal class ObjCFactoryMethodForKotlinArrayConstructor(
|
||||||
|
val irConstructorSymbol: IrConstructorSymbol
|
||||||
|
) : ObjCMethodSpec()
|
||||||
|
|
||||||
|
internal class ObjCGetterForKotlinEnumEntry(val irEnumEntrySymbol: IrEnumEntrySymbol) : ObjCMethodSpec()
|
||||||
|
|
||||||
|
internal sealed class ObjCTypeSpec(val binaryName: String)
|
||||||
|
|
||||||
|
internal sealed class ObjCTypeForKotlinType(
|
||||||
|
binaryName: String,
|
||||||
|
val irClassSymbol: IrClassSymbol,
|
||||||
|
val methods: List<ObjCMethodSpec>
|
||||||
|
) : ObjCTypeSpec(binaryName)
|
||||||
|
|
||||||
|
internal class ObjCClassForKotlinClass(
|
||||||
|
binaryName: String,
|
||||||
|
irClassSymbol: IrClassSymbol,
|
||||||
|
methods: List<ObjCMethodSpec>,
|
||||||
|
val categoryMethods: List<ObjCMethodForKotlinMethod>,
|
||||||
|
val superClassNotAny: ObjCClassForKotlinClass?
|
||||||
|
) : ObjCTypeForKotlinType(binaryName, irClassSymbol, methods)
|
||||||
|
|
||||||
|
internal class ObjCProtocolForKotlinInterface(
|
||||||
|
binaryName: String,
|
||||||
|
irClassSymbol: IrClassSymbol,
|
||||||
|
methods: List<ObjCMethodSpec>
|
||||||
|
) : ObjCTypeForKotlinType(binaryName, irClassSymbol, methods)
|
||||||
|
|
||||||
|
internal class ObjCClassForKotlinFile(
|
||||||
|
binaryName: String,
|
||||||
|
val methods: List<ObjCMethodForKotlinMethod>
|
||||||
|
) : ObjCTypeSpec(binaryName)
|
||||||
+13
-6
@@ -7,9 +7,13 @@ package org.jetbrains.kotlin.backend.konan.objcexport
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.reportCompilationWarning
|
import org.jetbrains.kotlin.backend.konan.reportCompilationWarning
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageUtil
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.ir.util.report
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
|
|
||||||
internal class ObjCExportHeaderGeneratorImpl(
|
internal class ObjCExportHeaderGeneratorImpl(
|
||||||
val context: Context,
|
val context: Context,
|
||||||
@@ -23,10 +27,13 @@ internal class ObjCExportHeaderGeneratorImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun reportWarning(method: FunctionDescriptor, text: String) {
|
override fun reportWarning(method: FunctionDescriptor, text: String) {
|
||||||
context.report(
|
val psi = (method as? DeclarationDescriptorWithSource)?.source?.getPsi()
|
||||||
context.ir.get(method),
|
?: return reportWarning(
|
||||||
text,
|
"$text\n (at ${DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(method)})"
|
||||||
isError = false
|
)
|
||||||
)
|
|
||||||
|
val location = MessageUtil.psiElementToMessageLocation(psi)
|
||||||
|
|
||||||
|
context.messageCollector.report(CompilerMessageSeverity.WARNING, text, location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user