Improve kotlin.Unit support in produced framework

Make the Objective-C wrapper unique, and provide the method to get it
This commit is contained in:
Svyatoslav Scherbina
2017-12-07 14:00:45 +03:00
committed by SvyatoslavScherbina
parent 7696f41f6c
commit 0d082d6730
6 changed files with 64 additions and 6 deletions
@@ -398,6 +398,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val Kotlin_ObjCExport_refFromObjC by lazyRtFunction val Kotlin_ObjCExport_refFromObjC by lazyRtFunction
val Kotlin_Interop_CreateNSStringFromKString by lazyRtFunction val Kotlin_Interop_CreateNSStringFromKString by lazyRtFunction
val Kotlin_Interop_CreateNSArrayFromKList by lazyRtFunction val Kotlin_Interop_CreateNSArrayFromKList by lazyRtFunction
val Kotlin_ObjCExport_convertUnit by lazyRtFunction
val Kotlin_ObjCExport_GetAssociatedObject by lazyRtFunction val Kotlin_ObjCExport_GetAssociatedObject by lazyRtFunction
val Kotlin_ObjCExport_AbstractMethodCalled by lazyRtFunction val Kotlin_ObjCExport_AbstractMethodCalled by lazyRtFunction
@@ -254,6 +254,7 @@ internal class ObjCExportCodeGenerator(
methodTable: List<RTTIGenerator.MethodTableRecord>, methodTable: List<RTTIGenerator.MethodTableRecord>,
val objCName: String, val objCName: String,
directAdapters: List<ObjCToKotlinMethodAdapter>, directAdapters: List<ObjCToKotlinMethodAdapter>,
classAdapters: List<ObjCToKotlinMethodAdapter>,
virtualAdapters: List<ObjCToKotlinMethodAdapter>, virtualAdapters: List<ObjCToKotlinMethodAdapter>,
reverseAdapters: List<KotlinToObjCMethodAdapter> reverseAdapters: List<KotlinToObjCMethodAdapter>
) : Struct( ) : Struct(
@@ -275,6 +276,13 @@ internal class ObjCExportCodeGenerator(
), ),
Int32(directAdapters.size), Int32(directAdapters.size),
staticData.placeGlobalConstArray(
"",
runtime.objCToKotlinMethodAdapter,
classAdapters
),
Int32(classAdapters.size),
staticData.placeGlobalConstArray( staticData.placeGlobalConstArray(
"", "",
runtime.objCToKotlinMethodAdapter, runtime.objCToKotlinMethodAdapter,
@@ -611,7 +619,8 @@ private fun ObjCExportCodeGenerator.createTypeAdapterForPackage(
vtableSize = -1, vtableSize = -1,
methodTable = emptyList(), methodTable = emptyList(),
objCName = name, objCName = name,
directAdapters = adapters, directAdapters = emptyList(),
classAdapters = adapters,
virtualAdapters = emptyList(), virtualAdapters = emptyList(),
reverseAdapters = emptyList() reverseAdapters = emptyList()
) )
@@ -719,6 +728,12 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
emptyList() emptyList()
} }
val classAdapters = mutableListOf<ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter>()
if (descriptor.isUnit()) {
classAdapters += createUnitInstanceAdapter()
}
return ObjCTypeAdapter( return ObjCTypeAdapter(
descriptor, descriptor,
typeInfo, typeInfo,
@@ -727,11 +742,26 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
methodTable, methodTable,
objCName, objCName,
adapters, adapters,
classAdapters,
virtualAdapters, virtualAdapters,
reverseAdapters 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<CallableMemberDescriptor>.toMethods(): List<FunctionDescriptor> = this.flatMap { private fun List<CallableMemberDescriptor>.toMethods(): List<FunctionDescriptor> = this.flatMap {
when (it) { when (it) {
is PropertyDescriptor -> listOfNotNull(it.getter, it.setter) is PropertyDescriptor -> listOfNotNull(it.getter, it.setter)
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanCompilationException import org.jetbrains.kotlin.backend.konan.KonanCompilationException
import org.jetbrains.kotlin.backend.konan.descriptors.getPackageFragments import org.jetbrains.kotlin.backend.konan.descriptors.getPackageFragments
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface 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.backend.konan.reportCompilationError
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
@@ -201,6 +202,11 @@ internal class ObjCExportHeaderGenerator(val context: Context) {
+"@interface $name : $superName${descriptor.superProtocolsClause}" +"@interface $name : $superName${descriptor.superProtocolsClause}"
if (descriptor.isUnit()) {
+"+ (instancetype)unit NS_SWIFT_NAME(init());"
+""
}
val presentConstructors = mutableSetOf<String>() val presentConstructors = mutableSetOf<String>()
descriptor.constructors.filter { mapper.shouldBeExposed(it) }.forEach { descriptor.constructors.filter { mapper.shouldBeExposed(it) }.forEach {
+24 -5
View File
@@ -27,6 +27,7 @@
#import <Foundation/NSMethodSignature.h> #import <Foundation/NSMethodSignature.h>
#import <Foundation/NSException.h> #import <Foundation/NSException.h>
#import <objc/runtime.h> #import <objc/runtime.h>
#import <dispatch/dispatch.h>
#import "MemoryPrivate.hpp" #import "MemoryPrivate.hpp"
#import "Runtime.h" #import "Runtime.h"
#import "Utils.h" #import "Utils.h"
@@ -58,6 +59,9 @@ struct ObjCTypeAdapter {
const ObjCToKotlinMethodAdapter* directAdapters; const ObjCToKotlinMethodAdapter* directAdapters;
int directAdapterNum; int directAdapterNum;
const ObjCToKotlinMethodAdapter* classAdapters;
int classAdapterNum;
const ObjCToKotlinMethodAdapter* virtualAdapters; const ObjCToKotlinMethodAdapter* virtualAdapters;
int virtualAdapterNum; int virtualAdapterNum;
@@ -107,6 +111,7 @@ inline static OBJ_GETTER(AllocInstanceWithAssociatedObject, const TypeInfo* type
return result; return result;
} }
static Class getOrCreateClass(const TypeInfo* typeInfo);
static void initializeClass(Class clazz); static void initializeClass(Class clazz);
@protocol ConvertibleToKotlin @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( static const ObjCTypeAdapter* findAdapterByName(
const char* name, const char* name,
const ObjCTypeAdapter** sortedAdapters, const ObjCTypeAdapter** sortedAdapters,
@@ -279,8 +294,14 @@ static void initializeClass(Class clazz) {
for (int i = 0; i < typeAdapter->directAdapterNum; ++i) { for (int i = 0; i < typeAdapter->directAdapterNum; ++i) {
const ObjCToKotlinMethodAdapter* adapter = typeAdapter->directAdapters + i; const ObjCToKotlinMethodAdapter* adapter = typeAdapter->directAdapters + i;
SEL selector = sel_registerName(adapter->selector); SEL selector = sel_registerName(adapter->selector);
Class methodContainer = isClassForPackage ? object_getClass(clazz) : clazz; BOOL added = class_addMethod(clazz, selector, adapter->imp, adapter->encoding);
BOOL added = class_addMethod(methodContainer, 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"); RuntimeAssert(added, "Unexpected selector clash");
} }
@@ -570,8 +591,6 @@ extern "C" OBJ_GETTER(Kotlin_ObjCExport_refFromObjC, id obj) {
return [convertible toKotlin:OBJ_RESULT]; return [convertible toKotlin:OBJ_RESULT];
} }
static Class getOrCreateClass(const TypeInfo* typeInfo);
static id convertKotlinObject(ObjHeader* obj) { static id convertKotlinObject(ObjHeader* obj) {
Class clazz = obj->type_info()->writableInfo_->objCExport.objCClass; Class clazz = obj->type_info()->writableInfo_->objCExport.objCClass;
RuntimeAssert(clazz != nullptr, ""); RuntimeAssert(clazz != nullptr, "");
@@ -589,7 +608,7 @@ static id Kotlin_ObjCExport_refToObjC_slowpath(ObjHeader* obj) {
if (converter == nullptr) { if (converter == nullptr) {
getOrCreateClass(typeInfo); getOrCreateClass(typeInfo);
converter = &convertKotlinObject; converter = (typeInfo == theUnitTypeInfo) ? &Kotlin_ObjCExport_convertUnit : &convertKotlinObject;
} }
typeInfo->writableInfo_->objCExport.convert = converter; typeInfo->writableInfo_->objCExport.convert = converter;
+1
View File
@@ -83,6 +83,7 @@ extern const TypeInfo* theDoubleArrayTypeInfo;
extern const TypeInfo* theBooleanArrayTypeInfo; extern const TypeInfo* theBooleanArrayTypeInfo;
extern const TypeInfo* theStringTypeInfo; extern const TypeInfo* theStringTypeInfo;
extern const TypeInfo* theThrowableTypeInfo; extern const TypeInfo* theThrowableTypeInfo;
extern const TypeInfo* theUnitTypeInfo;
extern const TypeInfo* theObjCPointerHolderTypeInfo; extern const TypeInfo* theObjCPointerHolderTypeInfo;
KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) RUNTIME_PURE; KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) RUNTIME_PURE;
+1
View File
@@ -16,6 +16,7 @@
package kotlin package kotlin
@ExportTypeInfo("theUnitTypeInfo")
public object Unit { public object Unit {
override fun toString() = "kotlin.Unit" override fun toString() = "kotlin.Unit"
} }