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:
committed by
SvyatoslavScherbina
parent
7696f41f6c
commit
0d082d6730
+1
@@ -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
|
||||||
|
|
||||||
|
|||||||
+31
-1
@@ -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)
|
||||||
|
|||||||
+6
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user