Add prelimitary support for using Objective-C types in framework API

This commit is contained in:
Svyatoslav Scherbina
2018-04-02 11:10:50 +03:00
committed by SvyatoslavScherbina
parent 80d026afa5
commit 7d7f0f46e6
12 changed files with 97 additions and 37 deletions
@@ -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()
@@ -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)
@@ -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,
@@ -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()
@@ -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
@@ -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