diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 21f94d890e5..759da100dde 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -398,6 +398,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { val Kotlin_ObjCExport_refFromObjC by lazyRtFunction val Kotlin_Interop_CreateNSStringFromKString by lazyRtFunction val Kotlin_Interop_CreateNSArrayFromKList by lazyRtFunction + val Kotlin_ObjCExport_convertUnit by lazyRtFunction val Kotlin_ObjCExport_GetAssociatedObject by lazyRtFunction val Kotlin_ObjCExport_AbstractMethodCalled by lazyRtFunction diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index a91831c3354..e22593aaac9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -254,6 +254,7 @@ internal class ObjCExportCodeGenerator( methodTable: List, val objCName: String, directAdapters: List, + classAdapters: List, virtualAdapters: List, reverseAdapters: List ) : Struct( @@ -275,6 +276,13 @@ internal class ObjCExportCodeGenerator( ), Int32(directAdapters.size), + staticData.placeGlobalConstArray( + "", + runtime.objCToKotlinMethodAdapter, + classAdapters + ), + Int32(classAdapters.size), + staticData.placeGlobalConstArray( "", runtime.objCToKotlinMethodAdapter, @@ -611,7 +619,8 @@ private fun ObjCExportCodeGenerator.createTypeAdapterForPackage( vtableSize = -1, methodTable = emptyList(), objCName = name, - directAdapters = adapters, + directAdapters = emptyList(), + classAdapters = adapters, virtualAdapters = emptyList(), reverseAdapters = emptyList() ) @@ -719,6 +728,12 @@ private fun ObjCExportCodeGenerator.createTypeAdapter( emptyList() } + val classAdapters = mutableListOf() + + if (descriptor.isUnit()) { + classAdapters += createUnitInstanceAdapter() + } + return ObjCTypeAdapter( descriptor, typeInfo, @@ -727,11 +742,26 @@ private fun ObjCExportCodeGenerator.createTypeAdapter( methodTable, objCName, adapters, + classAdapters, virtualAdapters, reverseAdapters ) } +private fun ObjCExportCodeGenerator.createUnitInstanceAdapter(): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter { + val selector = "unit" + val methodBridge = MethodBridge(ReferenceBridge, listOf(ReferenceBridge, ReferenceBridge)) + val encoding = getEncoding(methodBridge) + + val imp = generateFunction(codegen, objCFunctionType(methodBridge), "") { + ret(callFromBridge(context.llvm.Kotlin_ObjCExport_convertUnit, listOf(codegen.theUnitInstanceRef.llvm))) + } + + LLVMSetLinkage(imp, LLVMLinkage.LLVMPrivateLinkage) + + return ObjCToKotlinMethodAdapter(selector, encoding, constPointer(imp)) +} + private fun List.toMethods(): List = this.flatMap { when (it) { is PropertyDescriptor -> listOfNotNull(it.getter, it.setter) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt index 7374816a491..ace4db68824 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.KonanCompilationException import org.jetbrains.kotlin.backend.konan.descriptors.getPackageFragments import org.jetbrains.kotlin.backend.konan.descriptors.isInterface +import org.jetbrains.kotlin.backend.konan.descriptors.isUnit import org.jetbrains.kotlin.backend.konan.reportCompilationError import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType @@ -201,6 +202,11 @@ internal class ObjCExportHeaderGenerator(val context: Context) { +"@interface $name : $superName${descriptor.superProtocolsClause}" + if (descriptor.isUnit()) { + +"+ (instancetype)unit NS_SWIFT_NAME(init());" + +"" + } + val presentConstructors = mutableSetOf() descriptor.constructors.filter { mapper.shouldBeExposed(it) }.forEach { diff --git a/runtime/src/main/cpp/ObjCExport.mm b/runtime/src/main/cpp/ObjCExport.mm index 517077bfa6f..4beefd603c8 100644 --- a/runtime/src/main/cpp/ObjCExport.mm +++ b/runtime/src/main/cpp/ObjCExport.mm @@ -27,6 +27,7 @@ #import #import #import +#import #import "MemoryPrivate.hpp" #import "Runtime.h" #import "Utils.h" @@ -58,6 +59,9 @@ struct ObjCTypeAdapter { const ObjCToKotlinMethodAdapter* directAdapters; int directAdapterNum; + const ObjCToKotlinMethodAdapter* classAdapters; + int classAdapterNum; + const ObjCToKotlinMethodAdapter* virtualAdapters; int virtualAdapterNum; @@ -107,6 +111,7 @@ inline static OBJ_GETTER(AllocInstanceWithAssociatedObject, const TypeInfo* type return result; } +static Class getOrCreateClass(const TypeInfo* typeInfo); static void initializeClass(Class clazz); @protocol ConvertibleToKotlin @@ -200,6 +205,16 @@ extern "C" void Kotlin_ObjCExport_releaseReservedObjectTail(ObjHeader* obj) { } } +extern "C" id Kotlin_ObjCExport_convertUnit(ObjHeader* unitInstance) { + static dispatch_once_t onceToken; + static id instance = nullptr; + dispatch_once(&onceToken, ^{ + Class unitClass = getOrCreateClass(unitInstance->type_info()); + instance = [[unitClass createWrapper:unitInstance] retain]; + }); + return instance; +} + static const ObjCTypeAdapter* findAdapterByName( const char* name, const ObjCTypeAdapter** sortedAdapters, @@ -279,8 +294,14 @@ static void initializeClass(Class clazz) { for (int i = 0; i < typeAdapter->directAdapterNum; ++i) { const ObjCToKotlinMethodAdapter* adapter = typeAdapter->directAdapters + i; SEL selector = sel_registerName(adapter->selector); - Class methodContainer = isClassForPackage ? object_getClass(clazz) : clazz; - BOOL added = class_addMethod(methodContainer, selector, adapter->imp, adapter->encoding); + BOOL added = class_addMethod(clazz, selector, adapter->imp, adapter->encoding); + RuntimeAssert(added, "Unexpected selector clash"); + } + + for (int i = 0; i < typeAdapter->classAdapterNum; ++i) { + const ObjCToKotlinMethodAdapter* adapter = typeAdapter->classAdapters + i; + SEL selector = sel_registerName(adapter->selector); + BOOL added = class_addMethod(object_getClass(clazz), selector, adapter->imp, adapter->encoding); RuntimeAssert(added, "Unexpected selector clash"); } @@ -570,8 +591,6 @@ extern "C" OBJ_GETTER(Kotlin_ObjCExport_refFromObjC, id obj) { return [convertible toKotlin:OBJ_RESULT]; } -static Class getOrCreateClass(const TypeInfo* typeInfo); - static id convertKotlinObject(ObjHeader* obj) { Class clazz = obj->type_info()->writableInfo_->objCExport.objCClass; RuntimeAssert(clazz != nullptr, ""); @@ -589,7 +608,7 @@ static id Kotlin_ObjCExport_refToObjC_slowpath(ObjHeader* obj) { if (converter == nullptr) { getOrCreateClass(typeInfo); - converter = &convertKotlinObject; + converter = (typeInfo == theUnitTypeInfo) ? &Kotlin_ObjCExport_convertUnit : &convertKotlinObject; } typeInfo->writableInfo_->objCExport.convert = converter; diff --git a/runtime/src/main/cpp/Types.h b/runtime/src/main/cpp/Types.h index f2842db5f49..2219cc818b4 100644 --- a/runtime/src/main/cpp/Types.h +++ b/runtime/src/main/cpp/Types.h @@ -83,6 +83,7 @@ extern const TypeInfo* theDoubleArrayTypeInfo; extern const TypeInfo* theBooleanArrayTypeInfo; extern const TypeInfo* theStringTypeInfo; extern const TypeInfo* theThrowableTypeInfo; +extern const TypeInfo* theUnitTypeInfo; extern const TypeInfo* theObjCPointerHolderTypeInfo; KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) RUNTIME_PURE; diff --git a/runtime/src/main/kotlin/kotlin/Unit.kt b/runtime/src/main/kotlin/kotlin/Unit.kt index 71ffe1a3543..bfa46829d3e 100644 --- a/runtime/src/main/kotlin/kotlin/Unit.kt +++ b/runtime/src/main/kotlin/kotlin/Unit.kt @@ -16,6 +16,7 @@ package kotlin +@ExportTypeInfo("theUnitTypeInfo") public object Unit { override fun toString() = "kotlin.Unit" } \ No newline at end of file