Add prelimitary support for using Objective-C types in framework API
This commit is contained in:
committed by
SvyatoslavScherbina
parent
80d026afa5
commit
7d7f0f46e6
+2
-3
@@ -172,10 +172,9 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
|
||||
|
||||
val getObjCClass = packageScope.getContributedFunctions("getObjCClass").single()
|
||||
|
||||
val objCObjectRawPtr = packageScope.getContributedVariables("rawPtr").single {
|
||||
val objCObjectRawPtr = packageScope.getContributedFunctions("rawPtr").single {
|
||||
val extensionReceiverType = it.extensionReceiverParameter?.type
|
||||
extensionReceiverType != null && !extensionReceiverType.isMarkedNullable &&
|
||||
TypeUtils.getClassDescriptor(extensionReceiverType) == objCObject
|
||||
extensionReceiverType != null && TypeUtils.getClassDescriptor(extensionReceiverType) == objCObject
|
||||
}
|
||||
|
||||
val getObjCReceiverOrSuper = packageScope.getContributedFunctions("getReceiverOrSuper").single()
|
||||
|
||||
+1
-1
@@ -117,7 +117,7 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
|
||||
symbolTable.referenceSimpleFunction(context.interopBuiltIns.objCObjectSuperInitCheck)
|
||||
|
||||
val interopObjCObjectRawValueGetter =
|
||||
symbolTable.referenceSimpleFunction(context.interopBuiltIns.objCObjectRawPtr.getter!!)
|
||||
symbolTable.referenceSimpleFunction(context.interopBuiltIns.objCObjectRawPtr)
|
||||
|
||||
val interopInvokeImpls = context.interopBuiltIns.invokeImpls.mapValues { (_, function) ->
|
||||
symbolTable.referenceSimpleFunction(function)
|
||||
|
||||
+9
@@ -440,6 +440,15 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
null
|
||||
}
|
||||
|
||||
val objCExportEnabled = if (context.config.produce.isNativeBinary) {
|
||||
// Note: this defines the global declared in runtime (if any).
|
||||
staticData.placeGlobal("objCExportEnabled", Int8(0), isExported = true).also {
|
||||
it.setConstant(true)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val tlsMode by lazy {
|
||||
when (target) {
|
||||
KonanTarget.WASM32,
|
||||
|
||||
+6
@@ -218,6 +218,7 @@ internal class ObjCExportCodeGenerator(
|
||||
emitSortedAdapters(placedInterfaceAdapters, "Kotlin_ObjCExport_sortedProtocolAdapters")
|
||||
|
||||
context.llvm.kObjectReservedTailSize!!.setInitializer(Int32(runtime.pointerSize))
|
||||
context.llvm.objCExportEnabled!!.setInitializer(Int8(1))
|
||||
|
||||
dataGenerator.finishModule() // TODO: move to appropriate place.
|
||||
}
|
||||
@@ -445,6 +446,11 @@ private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
|
||||
emitBoxConverter(it)
|
||||
}
|
||||
|
||||
setObjCExportTypeInfo(
|
||||
context.interopBuiltIns.objCPointerHolder,
|
||||
constPointer(codegen.llvmFunction(context.ir.symbols.objCPointerHolderValueGetter.owner))
|
||||
)
|
||||
|
||||
emitFunctionConverters()
|
||||
|
||||
emitKotlinFunctionAdaptersToBlock()
|
||||
|
||||
+43
-16
@@ -92,8 +92,11 @@ internal class ObjCExportHeaderGenerator(val context: Context) {
|
||||
private val kotlinAnyName = namer.kotlinAnyName
|
||||
|
||||
private val stubs = mutableListOf<Stub>()
|
||||
private val classToName = mutableMapOf<ClassDescriptor, String>()
|
||||
private val interfaceToName = mutableMapOf<ClassDescriptor, String>()
|
||||
private val classOrInterfaceToName = mutableMapOf<ClassDescriptor, String>()
|
||||
|
||||
internal val classForwardDeclarations = mutableSetOf<String>()
|
||||
internal val protocolForwardDeclarations = mutableSetOf<String>()
|
||||
|
||||
private val extensions = mutableMapOf<ClassDescriptor, MutableList<CallableMemberDescriptor>>()
|
||||
val extraClassesToTranslate = mutableSetOf<ClassDescriptor>()
|
||||
|
||||
@@ -154,17 +157,11 @@ internal class ObjCExportHeaderGenerator(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun translateClassName(descriptor: ClassDescriptor): String {
|
||||
val descriptorToName = if (descriptor.isInterface) interfaceToName else classToName
|
||||
fun translateClassName(descriptor: ClassDescriptor): String = classOrInterfaceToName.getOrPut(descriptor) {
|
||||
assert(mapper.shouldBeExposed(descriptor))
|
||||
val forwardDeclarations = if (descriptor.isInterface) protocolForwardDeclarations else classForwardDeclarations
|
||||
|
||||
return descriptorToName.getOrPut(descriptor) {
|
||||
if (!mapper.shouldBeExposed(descriptor)) {
|
||||
context.reportCompilationError("Can't produce ${descriptor.fqNameSafe.asString()} to framework API")
|
||||
throw KonanCompilationException()
|
||||
}
|
||||
|
||||
namer.getClassOrProtocolName(descriptor)
|
||||
}
|
||||
namer.getClassOrProtocolName(descriptor).also { forwardDeclarations += it }
|
||||
}
|
||||
|
||||
private fun translateInterface(descriptor: ClassDescriptor) {
|
||||
@@ -555,13 +552,13 @@ internal class ObjCExportHeaderGenerator(val context: Context) {
|
||||
add("#import <Foundation/Foundation.h>")
|
||||
add("")
|
||||
|
||||
if (classToName.isNotEmpty()) {
|
||||
add("@class ${classToName.values.joinToString()};")
|
||||
if (classForwardDeclarations.isNotEmpty()) {
|
||||
add("@class ${classForwardDeclarations.joinToString()};")
|
||||
add("")
|
||||
}
|
||||
|
||||
if (interfaceToName.isNotEmpty()) {
|
||||
add("@protocol ${interfaceToName.values.joinToString()};")
|
||||
if (protocolForwardDeclarations.isNotEmpty()) {
|
||||
add("@protocol ${protocolForwardDeclarations.joinToString()};")
|
||||
add("")
|
||||
}
|
||||
|
||||
@@ -790,6 +787,10 @@ private fun ObjCExportHeaderGenerator.mapReferenceTypeIgnoringNullability(
|
||||
return ObjCIdType
|
||||
}
|
||||
|
||||
if (classDescriptor.defaultType.isObjCObjectType()) {
|
||||
return mapObjCObjectReferenceTypeIgnoringNullability(classDescriptor)
|
||||
}
|
||||
|
||||
scheduleClassToBeGenerated(classDescriptor)
|
||||
|
||||
return if (classDescriptor.isInterface) {
|
||||
@@ -799,6 +800,32 @@ private fun ObjCExportHeaderGenerator.mapReferenceTypeIgnoringNullability(
|
||||
}
|
||||
}
|
||||
|
||||
private tailrec fun ObjCExportHeaderGenerator.mapObjCObjectReferenceTypeIgnoringNullability(
|
||||
descriptor: ClassDescriptor
|
||||
): ObjCNonNullReferenceType {
|
||||
// TODO: more precise types can be used.
|
||||
|
||||
if (descriptor.isObjCMetaClass()) return ObjCIdType
|
||||
|
||||
if (descriptor.isExternalObjCClass()) {
|
||||
return if (descriptor.isInterface) {
|
||||
val name = descriptor.name.asString().removeSuffix("Protocol")
|
||||
protocolForwardDeclarations += name
|
||||
ObjCProtocolType(name)
|
||||
} else {
|
||||
val name = descriptor.name.asString()
|
||||
classForwardDeclarations += name
|
||||
ObjCClassType(name)
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor.isKotlinObjCClass()) {
|
||||
return mapObjCObjectReferenceTypeIgnoringNullability(descriptor.getSuperClassOrAny())
|
||||
}
|
||||
|
||||
return ObjCIdType
|
||||
}
|
||||
|
||||
private fun ObjCExportHeaderGenerator.scheduleClassToBeGenerated(classDescriptor: ClassDescriptor) {
|
||||
if (classDescriptor !in generatedClasses) {
|
||||
extraClassesToTranslate += classDescriptor
|
||||
|
||||
+2
@@ -49,6 +49,8 @@ internal fun ObjCExportMapper.getClassIfCategory(descriptor: CallableMemberDescr
|
||||
|
||||
val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return null
|
||||
|
||||
if (extensionReceiverType.isObjCObjectType()) return null
|
||||
|
||||
val erasedClass = extensionReceiverType.getErasedTypeClass()
|
||||
return if (this.isRepresentedAsObjCInterface(erasedClass)) {
|
||||
erasedClass
|
||||
|
||||
Reference in New Issue
Block a user