Move all Objective-C global names to objc.bc
This commit is contained in:
committed by
SvyatoslavScherbina
parent
a40604b640
commit
c32fa6313b
@@ -20,6 +20,17 @@ inline static void SetAssociatedObject(ObjHeader* obj, id value) {
|
|||||||
obj->meta_object()->associatedObject_ = (void*)value;
|
obj->meta_object()->associatedObject_ = (void*)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static id AtomicCompareAndSwapAssociatedObject(ObjHeader* obj, id expectedValue, id newValue) {
|
||||||
|
id* location = reinterpret_cast<id*>(&obj->meta_object()->associatedObject_);
|
||||||
|
return __sync_val_compare_and_swap(location, expectedValue, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static OBJ_GETTER(AllocInstanceWithAssociatedObject, const TypeInfo* typeInfo, id associatedObject) {
|
||||||
|
ObjHeader* result = AllocInstance(typeInfo, OBJ_RESULT);
|
||||||
|
SetAssociatedObject(result, associatedObject);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" id Kotlin_ObjCExport_refToObjC(ObjHeader* obj);
|
extern "C" id Kotlin_ObjCExport_refToObjC(ObjHeader* obj);
|
||||||
extern "C" OBJ_GETTER(Kotlin_ObjCExport_refFromObjC, id obj);
|
extern "C" OBJ_GETTER(Kotlin_ObjCExport_refFromObjC, id obj);
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "Atomic.h"
|
|
||||||
#import "Types.h"
|
#import "Types.h"
|
||||||
#import "Memory.h"
|
#import "Memory.h"
|
||||||
#import "MemorySharedRefs.hpp"
|
|
||||||
#include "Natives.h"
|
#include "Natives.h"
|
||||||
|
|
||||||
#if KONAN_OBJC_INTEROP
|
#if KONAN_OBJC_INTEROP
|
||||||
@@ -32,11 +30,13 @@
|
|||||||
#import <Foundation/NSException.h>
|
#import <Foundation/NSException.h>
|
||||||
#import <Foundation/NSDecimalNumber.h>
|
#import <Foundation/NSDecimalNumber.h>
|
||||||
#import <Foundation/NSDictionary.h>
|
#import <Foundation/NSDictionary.h>
|
||||||
|
#import <objc/message.h>
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
#import <objc/objc-exception.h>
|
#import <objc/objc-exception.h>
|
||||||
#import <dispatch/dispatch.h>
|
#import <dispatch/dispatch.h>
|
||||||
|
|
||||||
#import "ObjCExport.h"
|
#import "ObjCExport.h"
|
||||||
|
#import "ObjCExportPrivate.h"
|
||||||
#import "MemoryPrivate.hpp"
|
#import "MemoryPrivate.hpp"
|
||||||
#import "Runtime.h"
|
#import "Runtime.h"
|
||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
@@ -99,7 +99,7 @@ struct WritableTypeInfo {
|
|||||||
|
|
||||||
static char associatedTypeInfoKey;
|
static char associatedTypeInfoKey;
|
||||||
|
|
||||||
static const TypeInfo* getAssociatedTypeInfo(Class clazz) {
|
extern "C" const TypeInfo* Kotlin_ObjCExport_getAssociatedTypeInfo(Class clazz) {
|
||||||
return (const TypeInfo*)[objc_getAssociatedObject(clazz, &associatedTypeInfoKey) pointerValue];
|
return (const TypeInfo*)[objc_getAssociatedObject(clazz, &associatedTypeInfoKey) pointerValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,12 +111,6 @@ extern "C" id Kotlin_ObjCExport_GetAssociatedObject(ObjHeader* obj) {
|
|||||||
return GetAssociatedObject(obj);
|
return GetAssociatedObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static OBJ_GETTER(AllocInstanceWithAssociatedObject, const TypeInfo* typeInfo, id associatedObject) {
|
|
||||||
ObjHeader* result = AllocInstance(typeInfo, OBJ_RESULT);
|
|
||||||
SetAssociatedObject(result, associatedObject);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" OBJ_GETTER(Kotlin_ObjCExport_AllocInstanceWithAssociatedObject,
|
extern "C" OBJ_GETTER(Kotlin_ObjCExport_AllocInstanceWithAssociatedObject,
|
||||||
const TypeInfo* typeInfo, id associatedObject) RUNTIME_NOTHROW;
|
const TypeInfo* typeInfo, id associatedObject) RUNTIME_NOTHROW;
|
||||||
|
|
||||||
@@ -129,122 +123,12 @@ static Class getOrCreateClass(const TypeInfo* typeInfo);
|
|||||||
static void initializeClass(Class clazz);
|
static void initializeClass(Class clazz);
|
||||||
extern "C" ALWAYS_INLINE void Kotlin_ObjCExport_releaseAssociatedObject(void* associatedObject);
|
extern "C" ALWAYS_INLINE void Kotlin_ObjCExport_releaseAssociatedObject(void* associatedObject);
|
||||||
|
|
||||||
static inline id AtomicCompareAndSwapAssociatedObject(ObjHeader* obj, id expectedValue, id newValue) {
|
|
||||||
id* location = reinterpret_cast<id*>(&obj->meta_object()->associatedObject_);
|
|
||||||
return __sync_val_compare_and_swap(location, expectedValue, newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" id objc_retainAutoreleaseReturnValue(id self);
|
extern "C" id objc_retainAutoreleaseReturnValue(id self);
|
||||||
extern "C" id objc_autoreleaseReturnValue(id self);
|
|
||||||
|
|
||||||
@interface NSObject (NSObjectPrivateMethods)
|
|
||||||
// Implemented for NSObject in libobjc/NSObject.mm
|
|
||||||
-(BOOL)_tryRetain;
|
|
||||||
@end;
|
|
||||||
|
|
||||||
@interface KotlinBase : NSObject <ConvertibleToKotlin, NSCopying>
|
|
||||||
@end;
|
|
||||||
|
|
||||||
static void initializeObjCExport();
|
|
||||||
|
|
||||||
@implementation KotlinBase {
|
|
||||||
BackRefFromAssociatedObject refHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(KRef)toKotlin:(KRef*)OBJ_RESULT {
|
|
||||||
RETURN_OBJ(refHolder.ref());
|
|
||||||
}
|
|
||||||
|
|
||||||
+(void)initialize {
|
|
||||||
if (self == [KotlinBase class]) {
|
|
||||||
initializeObjCExport();
|
|
||||||
}
|
|
||||||
initializeClass(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
+(instancetype)allocWithZone:(NSZone*)zone {
|
|
||||||
Kotlin_initRuntimeIfNeeded();
|
|
||||||
|
|
||||||
KotlinBase* result = [super allocWithZone:zone];
|
|
||||||
|
|
||||||
const TypeInfo* typeInfo = getAssociatedTypeInfo(self);
|
|
||||||
if (typeInfo == nullptr) {
|
|
||||||
[NSException raise:NSGenericException
|
|
||||||
format:@"%s is not allocatable or +[KotlinBase initialize] method wasn't called on it",
|
|
||||||
class_getName(object_getClass(self))];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeInfo->instanceSize_ < 0) {
|
|
||||||
[NSException raise:NSGenericException
|
|
||||||
format:@"%s must be allocated and initialized with a factory method",
|
|
||||||
class_getName(object_getClass(self))];
|
|
||||||
}
|
|
||||||
ObjHolder holder;
|
|
||||||
AllocInstanceWithAssociatedObject(typeInfo, result, holder.slot());
|
|
||||||
result->refHolder.initAndAddRef(holder.obj());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
+(instancetype)createWrapper:(ObjHeader*)obj {
|
|
||||||
KotlinBase* candidate = [super allocWithZone:nil];
|
|
||||||
// TODO: should we call NSObject.init ?
|
|
||||||
candidate->refHolder.initAndAddRef(obj);
|
|
||||||
|
|
||||||
if (!obj->permanent()) { // TODO: permanent objects should probably be supported as custom types.
|
|
||||||
if (!obj->container()->shareable()) {
|
|
||||||
SetAssociatedObject(obj, candidate);
|
|
||||||
} else {
|
|
||||||
id old = AtomicCompareAndSwapAssociatedObject(obj, nullptr, candidate);
|
|
||||||
if (old != nullptr) {
|
|
||||||
candidate->refHolder.releaseRef();
|
|
||||||
[candidate releaseAsAssociatedObject];
|
|
||||||
return objc_retainAutoreleaseReturnValue(old);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return objc_autoreleaseReturnValue(candidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
-(instancetype)retain {
|
|
||||||
if (refHolder.permanent()) { // TODO: consider storing `isPermanent` to self field.
|
|
||||||
[super retain];
|
|
||||||
} else {
|
|
||||||
refHolder.addRef();
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(BOOL)_tryRetain {
|
|
||||||
if (refHolder.permanent()) {
|
|
||||||
return [super _tryRetain];
|
|
||||||
} else {
|
|
||||||
return refHolder.tryAddRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(oneway void)release {
|
|
||||||
if (refHolder.permanent()) {
|
|
||||||
[super release];
|
|
||||||
} else {
|
|
||||||
refHolder.releaseRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)releaseAsAssociatedObject {
|
|
||||||
[super release];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
|
||||||
// TODO: write documentation.
|
|
||||||
return [self retain];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end;
|
|
||||||
|
|
||||||
extern "C" ALWAYS_INLINE void Kotlin_ObjCExport_releaseAssociatedObject(void* associatedObject) {
|
extern "C" ALWAYS_INLINE void Kotlin_ObjCExport_releaseAssociatedObject(void* associatedObject) {
|
||||||
if (associatedObject != nullptr) {
|
if (associatedObject != nullptr) {
|
||||||
[((id)associatedObject) releaseAsAssociatedObject];
|
auto msgSend = reinterpret_cast<void (*)(void* self, SEL cmd)>(&objc_msgSend);
|
||||||
|
msgSend(associatedObject, Kotlin_ObjCExport_releaseAsAssociatedObjectSelector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +237,7 @@ static void addProtocolForInterface(Class clazz, const TypeInfo* interfaceInfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" const TypeInfo* Kotlin_ObjCInterop_getTypeInfoForClass(Class clazz) {
|
extern "C" const TypeInfo* Kotlin_ObjCInterop_getTypeInfoForClass(Class clazz) {
|
||||||
const TypeInfo* candidate = getAssociatedTypeInfo(clazz);
|
const TypeInfo* candidate = Kotlin_ObjCExport_getAssociatedTypeInfo(clazz);
|
||||||
|
|
||||||
if (candidate != nullptr && (candidate->flags_ & TF_OBJC_DYNAMIC) == 0) {
|
if (candidate != nullptr && (candidate->flags_ & TF_OBJC_DYNAMIC) == 0) {
|
||||||
return candidate;
|
return candidate;
|
||||||
@@ -370,7 +254,7 @@ extern "C" const TypeInfo* Kotlin_ObjCInterop_getTypeInfoForProtocol(Protocol* p
|
|||||||
|
|
||||||
static const TypeInfo* getOrCreateTypeInfo(Class clazz);
|
static const TypeInfo* getOrCreateTypeInfo(Class clazz);
|
||||||
|
|
||||||
static void initializeClass(Class clazz) {
|
extern "C" void Kotlin_ObjCExport_initializeClass(Class clazz) {
|
||||||
const ObjCTypeAdapter* typeAdapter = findClassAdapter(clazz);
|
const ObjCTypeAdapter* typeAdapter = findClassAdapter(clazz);
|
||||||
if (typeAdapter == nullptr) {
|
if (typeAdapter == nullptr) {
|
||||||
getOrCreateTypeInfo(clazz);
|
getOrCreateTypeInfo(clazz);
|
||||||
@@ -405,19 +289,21 @@ static void initializeClass(Class clazz) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALWAYS_INLINE OBJ_GETTER(convertUnmappedObjCObject, id obj) {
|
extern "C" ALWAYS_INLINE OBJ_GETTER(Kotlin_ObjCExport_convertUnmappedObjCObject, id obj) {
|
||||||
const TypeInfo* typeInfo = getOrCreateTypeInfo(object_getClass(obj));
|
const TypeInfo* typeInfo = getOrCreateTypeInfo(object_getClass(obj));
|
||||||
RETURN_RESULT_OF(AllocInstanceWithAssociatedObject, typeInfo, objc_retain(obj));
|
RETURN_RESULT_OF(AllocInstanceWithAssociatedObject, typeInfo, objc_retain(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialized by [ObjCExportClasses.mm].
|
||||||
|
extern "C" SEL Kotlin_ObjCExport_toKotlinSelector = nullptr;
|
||||||
|
extern "C" SEL Kotlin_ObjCExport_releaseAsAssociatedObjectSelector = nullptr;
|
||||||
|
|
||||||
static OBJ_GETTER(blockToKotlinImp, id self, SEL cmd);
|
static OBJ_GETTER(blockToKotlinImp, id self, SEL cmd);
|
||||||
static OBJ_GETTER(boxedBooleanToKotlinImp, NSNumber* self, SEL cmd);
|
static OBJ_GETTER(boxedBooleanToKotlinImp, NSNumber* self, SEL cmd);
|
||||||
|
|
||||||
static OBJ_GETTER(SwiftObject_toKotlinImp, id self, SEL cmd);
|
static OBJ_GETTER(SwiftObject_toKotlinImp, id self, SEL cmd);
|
||||||
static void SwiftObject_releaseAsAssociatedObjectImp(id self, SEL cmd);
|
static void SwiftObject_releaseAsAssociatedObjectImp(id self, SEL cmd);
|
||||||
|
|
||||||
static void checkLoadedOnce();
|
|
||||||
|
|
||||||
static void initTypeAdaptersFrom(const ObjCTypeAdapter** adapters, int count) {
|
static void initTypeAdaptersFrom(const ObjCTypeAdapter** adapters, int count) {
|
||||||
for (int index = 0; index < count; ++index) {
|
for (int index = 0; index < count; ++index) {
|
||||||
const ObjCTypeAdapter* adapter = adapters[index];
|
const ObjCTypeAdapter* adapter = adapters[index];
|
||||||
@@ -435,15 +321,15 @@ static void initTypeAdapters() {
|
|||||||
initTypeAdaptersFrom(Kotlin_ObjCExport_sortedProtocolAdapters, Kotlin_ObjCExport_sortedProtocolAdaptersNum);
|
initTypeAdaptersFrom(Kotlin_ObjCExport_sortedProtocolAdapters, Kotlin_ObjCExport_sortedProtocolAdaptersNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initializeObjCExport() {
|
extern "C" void Kotlin_ObjCExport_initialize() {
|
||||||
initTypeAdapters();
|
initTypeAdapters();
|
||||||
|
|
||||||
SEL toKotlinSelector = @selector(toKotlin:);
|
SEL toKotlinSelector = Kotlin_ObjCExport_toKotlinSelector;
|
||||||
Method toKotlinMethod = class_getClassMethod([NSObject class], toKotlinSelector);
|
Method toKotlinMethod = class_getClassMethod([NSObject class], toKotlinSelector);
|
||||||
RuntimeAssert(toKotlinMethod != nullptr, "");
|
RuntimeAssert(toKotlinMethod != nullptr, "");
|
||||||
const char* toKotlinTypeEncoding = method_getTypeEncoding(toKotlinMethod);
|
const char* toKotlinTypeEncoding = method_getTypeEncoding(toKotlinMethod);
|
||||||
|
|
||||||
SEL releaseAsAssociatedObjectSelector = @selector(releaseAsAssociatedObject);
|
SEL releaseAsAssociatedObjectSelector = Kotlin_ObjCExport_releaseAsAssociatedObjectSelector;
|
||||||
Method releaseAsAssociatedObjectMethod = class_getClassMethod([NSObject class], releaseAsAssociatedObjectSelector);
|
Method releaseAsAssociatedObjectMethod = class_getClassMethod([NSObject class], releaseAsAssociatedObjectSelector);
|
||||||
RuntimeAssert(releaseAsAssociatedObjectMethod != nullptr, "");
|
RuntimeAssert(releaseAsAssociatedObjectMethod != nullptr, "");
|
||||||
const char* releaseAsAssociatedObjectTypeEncoding = method_getTypeEncoding(releaseAsAssociatedObjectMethod);
|
const char* releaseAsAssociatedObjectTypeEncoding = method_getTypeEncoding(releaseAsAssociatedObjectMethod);
|
||||||
@@ -477,99 +363,21 @@ static void initializeObjCExport() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface NSObject (NSObjectToKotlin) <ConvertibleToKotlin>
|
|
||||||
@end;
|
|
||||||
|
|
||||||
@implementation NSObject (NSObjectToKotlin)
|
|
||||||
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
|
|
||||||
RETURN_RESULT_OF(convertUnmappedObjCObject, self);
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)releaseAsAssociatedObject {
|
|
||||||
objc_release(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
+(void)load {
|
|
||||||
static dispatch_once_t onceToken = 0;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
checkLoadedOnce();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@end;
|
|
||||||
|
|
||||||
static OBJ_GETTER(SwiftObject_toKotlinImp, id self, SEL cmd) {
|
static OBJ_GETTER(SwiftObject_toKotlinImp, id self, SEL cmd) {
|
||||||
RETURN_RESULT_OF(convertUnmappedObjCObject, self);
|
RETURN_RESULT_OF(Kotlin_ObjCExport_convertUnmappedObjCObject, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SwiftObject_releaseAsAssociatedObjectImp(id self, SEL cmd) {
|
static void SwiftObject_releaseAsAssociatedObjectImp(id self, SEL cmd) {
|
||||||
objc_release(self);
|
objc_release(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface NSString (NSStringToKotlin) <ConvertibleToKotlin>
|
|
||||||
@end;
|
|
||||||
|
|
||||||
@implementation NSString (NSStringToKotlin)
|
extern "C" OBJ_GETTER(Kotlin_boxBoolean, KBoolean value);
|
||||||
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
|
|
||||||
RETURN_RESULT_OF(Kotlin_Interop_CreateKStringFromNSString, self);
|
|
||||||
}
|
|
||||||
@end;
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_boxBoolean, KBoolean value);
|
|
||||||
OBJ_GETTER(Kotlin_boxByte, KByte value);
|
|
||||||
OBJ_GETTER(Kotlin_boxShort, KShort value);
|
|
||||||
OBJ_GETTER(Kotlin_boxInt, KInt value);
|
|
||||||
OBJ_GETTER(Kotlin_boxLong, KLong value);
|
|
||||||
OBJ_GETTER(Kotlin_boxUByte, KUByte value);
|
|
||||||
OBJ_GETTER(Kotlin_boxUShort, KUShort value);
|
|
||||||
OBJ_GETTER(Kotlin_boxUInt, KUInt value);
|
|
||||||
OBJ_GETTER(Kotlin_boxULong, KULong value);
|
|
||||||
OBJ_GETTER(Kotlin_boxFloat, KFloat value);
|
|
||||||
OBJ_GETTER(Kotlin_boxDouble, KDouble value);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static OBJ_GETTER(boxedBooleanToKotlinImp, NSNumber* self, SEL cmd) {
|
static OBJ_GETTER(boxedBooleanToKotlinImp, NSNumber* self, SEL cmd) {
|
||||||
RETURN_RESULT_OF(Kotlin_boxBoolean, self.boolValue);
|
RETURN_RESULT_OF(Kotlin_boxBoolean, self.boolValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface NSNumber (NSNumberToKotlin) <ConvertibleToKotlin>
|
|
||||||
@end;
|
|
||||||
|
|
||||||
@implementation NSNumber (NSNumberToKotlin)
|
|
||||||
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
|
|
||||||
const char* type = self.objCType;
|
|
||||||
|
|
||||||
// TODO: the code below makes some assumption on char, short, int and long sizes.
|
|
||||||
|
|
||||||
switch (type[0]) {
|
|
||||||
case 'c': RETURN_RESULT_OF(Kotlin_boxByte, self.charValue);
|
|
||||||
case 's': RETURN_RESULT_OF(Kotlin_boxShort, self.shortValue);
|
|
||||||
case 'i': RETURN_RESULT_OF(Kotlin_boxInt, self.intValue);
|
|
||||||
case 'q': RETURN_RESULT_OF(Kotlin_boxLong, self.longLongValue);
|
|
||||||
case 'C': RETURN_RESULT_OF(Kotlin_boxUByte, self.unsignedCharValue);
|
|
||||||
case 'S': RETURN_RESULT_OF(Kotlin_boxUShort, self.unsignedShortValue);
|
|
||||||
case 'I': RETURN_RESULT_OF(Kotlin_boxUInt, self.unsignedIntValue);
|
|
||||||
case 'Q': RETURN_RESULT_OF(Kotlin_boxULong, self.unsignedLongLongValue);
|
|
||||||
case 'f': RETURN_RESULT_OF(Kotlin_boxFloat, self.floatValue);
|
|
||||||
case 'd': RETURN_RESULT_OF(Kotlin_boxDouble, self.doubleValue);
|
|
||||||
|
|
||||||
default: RETURN_RESULT_OF(convertUnmappedObjCObject, self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end;
|
|
||||||
|
|
||||||
@interface NSDecimalNumber (NSDecimalNumberToKotlin) <ConvertibleToKotlin>
|
|
||||||
@end;
|
|
||||||
|
|
||||||
@implementation NSDecimalNumber (NSDecimalNumberToKotlin)
|
|
||||||
// Overrides [NSNumber toKotlin:] implementation.
|
|
||||||
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
|
|
||||||
RETURN_RESULT_OF(convertUnmappedObjCObject, self);
|
|
||||||
}
|
|
||||||
@end;
|
|
||||||
|
|
||||||
struct Block_descriptor_1;
|
struct Block_descriptor_1;
|
||||||
|
|
||||||
// Based on https://clang.llvm.org/docs/Block-ABI-Apple.html and libclosure source.
|
// Based on https://clang.llvm.org/docs/Block-ABI-Apple.html and libclosure source.
|
||||||
@@ -694,8 +502,8 @@ extern "C" OBJ_GETTER(Kotlin_Interop_CreateObjCObjectHolder, id obj) {
|
|||||||
|
|
||||||
extern "C" OBJ_GETTER(Kotlin_ObjCExport_refFromObjC, id obj) {
|
extern "C" OBJ_GETTER(Kotlin_ObjCExport_refFromObjC, id obj) {
|
||||||
if (obj == nullptr) RETURN_OBJ(nullptr);
|
if (obj == nullptr) RETURN_OBJ(nullptr);
|
||||||
id convertible = (id<ConvertibleToKotlin>)obj;
|
auto msgSend = reinterpret_cast<ObjHeader* (*)(id self, SEL cmd, ObjHeader** slot)>(&objc_msgSend);
|
||||||
return [convertible toKotlin:OBJ_RESULT];
|
RETURN_RESULT_OF(msgSend, obj, Kotlin_ObjCExport_toKotlinSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
static id convertKotlinObject(ObjHeader* obj) {
|
static id convertKotlinObject(ObjHeader* obj) {
|
||||||
@@ -1100,7 +908,7 @@ static const TypeInfo* createTypeInfo(Class clazz, const TypeInfo* superType) {
|
|||||||
static SimpleMutex typeInfoCreationMutex;
|
static SimpleMutex typeInfoCreationMutex;
|
||||||
|
|
||||||
static const TypeInfo* getOrCreateTypeInfo(Class clazz) {
|
static const TypeInfo* getOrCreateTypeInfo(Class clazz) {
|
||||||
const TypeInfo* result = getAssociatedTypeInfo(clazz);
|
const TypeInfo* result = Kotlin_ObjCExport_getAssociatedTypeInfo(clazz);
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1113,7 +921,7 @@ static const TypeInfo* getOrCreateTypeInfo(Class clazz) {
|
|||||||
|
|
||||||
LockGuard<SimpleMutex> lockGuard(typeInfoCreationMutex);
|
LockGuard<SimpleMutex> lockGuard(typeInfoCreationMutex);
|
||||||
|
|
||||||
result = getAssociatedTypeInfo(clazz); // double-checking.
|
result = Kotlin_ObjCExport_getAssociatedTypeInfo(clazz); // double-checking.
|
||||||
if (result == nullptr) {
|
if (result == nullptr) {
|
||||||
result = createTypeInfo(clazz, superType);
|
result = createTypeInfo(clazz, superType);
|
||||||
setAssociatedTypeInfo(clazz, result);
|
setAssociatedTypeInfo(clazz, result);
|
||||||
@@ -1214,16 +1022,6 @@ extern "C" void Kotlin_ObjCExport_AbstractMethodCalled(id self, SEL selector) {
|
|||||||
class_getName(object_getClass(self)), sel_getName(selector)];
|
class_getName(object_getClass(self)), sel_getName(selector)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkLoadedOnce() {
|
|
||||||
Class marker = objc_allocateClassPair([NSObject class], "KotlinFrameworkLoadedOnceMarker", 0);
|
|
||||||
if (marker == nullptr) {
|
|
||||||
[NSException raise:NSGenericException
|
|
||||||
format:@"Only one Kotlin framework can be loaded currently"];
|
|
||||||
} else {
|
|
||||||
objc_registerClassPair(marker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
extern "C" ALWAYS_INLINE void* Kotlin_Interop_refToObjC(ObjHeader* obj) {
|
extern "C" ALWAYS_INLINE void* Kotlin_Interop_refToObjC(ObjHeader* obj) {
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RUNTIME_OBJCEXPORTPRIVATE_H
|
||||||
|
#define RUNTIME_OBJCEXPORTPRIVATE_H
|
||||||
|
|
||||||
|
#if KONAN_OBJC_INTEROP
|
||||||
|
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
|
#import "Types.h"
|
||||||
|
#import "Memory.h"
|
||||||
|
#import "ObjCExport.h"
|
||||||
|
|
||||||
|
@interface KotlinBase : NSObject <ConvertibleToKotlin, NSCopying>
|
||||||
|
+(instancetype)createWrapper:(ObjHeader*)obj;
|
||||||
|
@end;
|
||||||
|
|
||||||
|
extern "C" void Kotlin_ObjCExport_initializeClass(Class clazz);
|
||||||
|
extern "C" void Kotlin_ObjCExport_initialize(void);
|
||||||
|
extern "C" const TypeInfo* Kotlin_ObjCExport_getAssociatedTypeInfo(Class clazz);
|
||||||
|
extern "C" OBJ_GETTER(Kotlin_ObjCExport_convertUnmappedObjCObject, id obj);
|
||||||
|
extern "C" SEL Kotlin_ObjCExport_toKotlinSelector;
|
||||||
|
extern "C" SEL Kotlin_ObjCExport_releaseAsAssociatedObjectSelector;
|
||||||
|
|
||||||
|
#endif // KONAN_OBJC_INTEROP
|
||||||
|
|
||||||
|
#endif // RUNTIME_OBJCEXPORTPRIVATE_H
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
#import <Foundation/NSException.h>
|
#import <Foundation/NSException.h>
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
#import "Memory.h"
|
#import "Memory.h"
|
||||||
#import "MemorySharedRefs.hpp"
|
#import "ObjCInteropUtilsPrivate.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Class nsStringClass = nullptr;
|
Class nsStringClass = nullptr;
|
||||||
@@ -97,49 +97,16 @@ id MissingInitImp(id self, SEL _cmd) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: rework the interface to reduce the number of virtual calls
|
// Initialized in [ObjCInteropUtilsClasses.mm].
|
||||||
// in Kotlin_Interop_createKotlinObjectHolder and Kotlin_Interop_unwrapKotlinObjectHolder
|
id (*Kotlin_Interop_createKotlinObjectHolder_ptr)(KRef any) = nullptr;
|
||||||
@interface KotlinObjectHolder : NSObject
|
KRef (*Kotlin_Interop_unwrapKotlinObjectHolder_ptr)(id holder) = nullptr;
|
||||||
-(id)initWithRef:(KRef)ref;
|
|
||||||
-(KRef)ref;
|
|
||||||
@end;
|
|
||||||
|
|
||||||
@implementation KotlinObjectHolder {
|
|
||||||
KRefSharedHolder refHolder;
|
|
||||||
};
|
|
||||||
|
|
||||||
-(id)initWithRef:(KRef)ref {
|
|
||||||
if (self = [super init]) {
|
|
||||||
refHolder.init(ref);
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(KRef)ref {
|
|
||||||
return refHolder.ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)dealloc {
|
|
||||||
refHolder.dispose();
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end;
|
|
||||||
|
|
||||||
id Kotlin_Interop_createKotlinObjectHolder(KRef any) {
|
id Kotlin_Interop_createKotlinObjectHolder(KRef any) {
|
||||||
if (any == nullptr) {
|
return Kotlin_Interop_createKotlinObjectHolder_ptr(any);
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [[[KotlinObjectHolder alloc] initWithRef:any] autorelease];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KRef Kotlin_Interop_unwrapKotlinObjectHolder(id holder) {
|
KRef Kotlin_Interop_unwrapKotlinObjectHolder(id holder) {
|
||||||
if (holder == nullptr) {
|
return Kotlin_Interop_unwrapKotlinObjectHolder_ptr(holder);
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [((KotlinObjectHolder*)holder) ref];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KBoolean Kotlin_Interop_DoesObjectConformToProtocol(id obj, void* prot, KBoolean isMeta) {
|
KBoolean Kotlin_Interop_DoesObjectConformToProtocol(id obj, void* prot, KBoolean isMeta) {
|
||||||
@@ -154,46 +121,15 @@ KBoolean Kotlin_Interop_IsObjectKindOfClass(id obj, void* cls) {
|
|||||||
return [((id<NSObject>)obj) isKindOfClass:(Class)cls];
|
return [((id<NSObject>)obj) isKindOfClass:(Class)cls];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used as an associated object for ObjCWeakReferenceImpl.
|
OBJ_GETTER((*Konan_ObjCInterop_getWeakReference_ptr), KRef ref) = nullptr;
|
||||||
@interface KotlinObjCWeakReference : NSObject
|
void (*Konan_ObjCInterop_initWeakReference_ptr)(KRef ref, id objcPtr) = nullptr;
|
||||||
@end;
|
|
||||||
|
|
||||||
// libobjc:
|
|
||||||
id objc_loadWeakRetained(id *location);
|
|
||||||
id objc_storeWeak(id *location, id newObj);
|
|
||||||
void objc_destroyWeak(id *location);
|
|
||||||
void objc_release(id obj);
|
|
||||||
|
|
||||||
@implementation KotlinObjCWeakReference {
|
|
||||||
@public id referred;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called when removing Kotlin object.
|
|
||||||
-(void)releaseAsAssociatedObject {
|
|
||||||
objc_destroyWeak(&referred);
|
|
||||||
objc_release(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end;
|
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_Interop_refFromObjC, id obj);
|
|
||||||
|
|
||||||
OBJ_GETTER(Konan_ObjCInterop_getWeakReference, KRef ref) {
|
OBJ_GETTER(Konan_ObjCInterop_getWeakReference, KRef ref) {
|
||||||
MetaObjHeader* meta = ref->meta_object();
|
RETURN_RESULT_OF(Konan_ObjCInterop_getWeakReference_ptr, ref);
|
||||||
KotlinObjCWeakReference* objcRef = (KotlinObjCWeakReference*)meta->associatedObject_;
|
|
||||||
|
|
||||||
id objcReferred = objc_loadWeakRetained(&objcRef->referred);
|
|
||||||
KRef result = Kotlin_Interop_refFromObjC(objcReferred, OBJ_RESULT);
|
|
||||||
objc_release(objcReferred);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Konan_ObjCInterop_initWeakReference(KRef ref, id objcPtr) {
|
void Konan_ObjCInterop_initWeakReference(KRef ref, id objcPtr) {
|
||||||
MetaObjHeader* meta = ref->meta_object();
|
Konan_ObjCInterop_initWeakReference_ptr(ref, objcPtr);
|
||||||
KotlinObjCWeakReference* objcRef = [KotlinObjCWeakReference new];
|
|
||||||
objc_storeWeak(&objcRef->referred, objcPtr);
|
|
||||||
meta->associatedObject_ = objcRef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RUNTIME_OBJCINTEROPUTILSPRIVATE_H
|
||||||
|
#define RUNTIME_OBJCINTEROPUTILSPRIVATE_H
|
||||||
|
|
||||||
|
#if KONAN_OBJC_INTEROP
|
||||||
|
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
|
#import "Types.h"
|
||||||
|
#import "Memory.h"
|
||||||
|
|
||||||
|
extern "C" id (*Kotlin_Interop_createKotlinObjectHolder_ptr)(KRef any);
|
||||||
|
extern "C" KRef (*Kotlin_Interop_unwrapKotlinObjectHolder_ptr)(id holder);
|
||||||
|
extern "C" OBJ_GETTER((*Konan_ObjCInterop_getWeakReference_ptr), KRef ref);
|
||||||
|
extern "C" void (*Konan_ObjCInterop_initWeakReference_ptr)(KRef ref, id objcPtr);
|
||||||
|
|
||||||
|
#endif // KONAN_OBJC_INTEROP
|
||||||
|
|
||||||
|
#endif // RUNTIME_OBJCINTEROPUTILSPRIVATE_H
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "Types.h"
|
||||||
|
#import "Memory.h"
|
||||||
|
#import "MemorySharedRefs.hpp"
|
||||||
|
|
||||||
|
#if KONAN_OBJC_INTEROP
|
||||||
|
|
||||||
|
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
|
||||||
|
|
||||||
|
#import <Foundation/NSObject.h>
|
||||||
|
#import <Foundation/NSValue.h>
|
||||||
|
#import <Foundation/NSString.h>
|
||||||
|
#import <Foundation/NSException.h>
|
||||||
|
#import <Foundation/NSDecimalNumber.h>
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#import <objc/objc-exception.h>
|
||||||
|
#import <dispatch/dispatch.h>
|
||||||
|
|
||||||
|
#import "ObjCExport.h"
|
||||||
|
#import "ObjCExportPrivate.h"
|
||||||
|
#import "MemoryPrivate.hpp"
|
||||||
|
#import "Runtime.h"
|
||||||
|
#import "Utils.h"
|
||||||
|
#import "Exceptions.h"
|
||||||
|
|
||||||
|
extern "C" id objc_retainAutoreleaseReturnValue(id self);
|
||||||
|
extern "C" id objc_autoreleaseReturnValue(id self);
|
||||||
|
|
||||||
|
@interface NSObject (NSObjectPrivateMethods)
|
||||||
|
// Implemented for NSObject in libobjc/NSObject.mm
|
||||||
|
-(BOOL)_tryRetain;
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@implementation KotlinBase {
|
||||||
|
BackRefFromAssociatedObject refHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(KRef)toKotlin:(KRef*)OBJ_RESULT {
|
||||||
|
RETURN_OBJ(refHolder.ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
+(void)initialize {
|
||||||
|
if (self == [KotlinBase class]) {
|
||||||
|
Kotlin_ObjCExport_initialize();
|
||||||
|
}
|
||||||
|
Kotlin_ObjCExport_initializeClass(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
+(instancetype)allocWithZone:(NSZone*)zone {
|
||||||
|
Kotlin_initRuntimeIfNeeded();
|
||||||
|
|
||||||
|
KotlinBase* result = [super allocWithZone:zone];
|
||||||
|
|
||||||
|
const TypeInfo* typeInfo = Kotlin_ObjCExport_getAssociatedTypeInfo(self);
|
||||||
|
if (typeInfo == nullptr) {
|
||||||
|
[NSException raise:NSGenericException
|
||||||
|
format:@"%s is not allocatable or +[KotlinBase initialize] method wasn't called on it",
|
||||||
|
class_getName(object_getClass(self))];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeInfo->instanceSize_ < 0) {
|
||||||
|
[NSException raise:NSGenericException
|
||||||
|
format:@"%s must be allocated and initialized with a factory method",
|
||||||
|
class_getName(object_getClass(self))];
|
||||||
|
}
|
||||||
|
ObjHolder holder;
|
||||||
|
AllocInstanceWithAssociatedObject(typeInfo, result, holder.slot());
|
||||||
|
result->refHolder.initAndAddRef(holder.obj());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
+(instancetype)createWrapper:(ObjHeader*)obj {
|
||||||
|
KotlinBase* candidate = [super allocWithZone:nil];
|
||||||
|
// TODO: should we call NSObject.init ?
|
||||||
|
candidate->refHolder.initAndAddRef(obj);
|
||||||
|
|
||||||
|
if (!obj->permanent()) { // TODO: permanent objects should probably be supported as custom types.
|
||||||
|
if (!obj->container()->shareable()) {
|
||||||
|
SetAssociatedObject(obj, candidate);
|
||||||
|
} else {
|
||||||
|
id old = AtomicCompareAndSwapAssociatedObject(obj, nullptr, candidate);
|
||||||
|
if (old != nullptr) {
|
||||||
|
candidate->refHolder.releaseRef();
|
||||||
|
[candidate releaseAsAssociatedObject];
|
||||||
|
return objc_retainAutoreleaseReturnValue(old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return objc_autoreleaseReturnValue(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
-(instancetype)retain {
|
||||||
|
if (refHolder.permanent()) { // TODO: consider storing `isPermanent` to self field.
|
||||||
|
[super retain];
|
||||||
|
} else {
|
||||||
|
refHolder.addRef();
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL)_tryRetain {
|
||||||
|
if (refHolder.permanent()) {
|
||||||
|
return [super _tryRetain];
|
||||||
|
} else {
|
||||||
|
return refHolder.tryAddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(oneway void)release {
|
||||||
|
if (refHolder.permanent()) {
|
||||||
|
[super release];
|
||||||
|
} else {
|
||||||
|
refHolder.releaseRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)releaseAsAssociatedObject {
|
||||||
|
[super release];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||||
|
// TODO: write documentation.
|
||||||
|
return [self retain];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@interface NSObject (NSObjectToKotlin) <ConvertibleToKotlin>
|
||||||
|
@end;
|
||||||
|
|
||||||
|
static void checkLoadedOnce();
|
||||||
|
|
||||||
|
@implementation NSObject (NSObjectToKotlin)
|
||||||
|
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
|
||||||
|
RETURN_RESULT_OF(Kotlin_ObjCExport_convertUnmappedObjCObject, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)releaseAsAssociatedObject {
|
||||||
|
objc_release(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
+(void)load {
|
||||||
|
static dispatch_once_t onceToken = 0;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
checkLoadedOnce();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@interface NSString (NSStringToKotlin) <ConvertibleToKotlin>
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@implementation NSString (NSStringToKotlin)
|
||||||
|
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
|
||||||
|
RETURN_RESULT_OF(Kotlin_Interop_CreateKStringFromNSString, self);
|
||||||
|
}
|
||||||
|
@end;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
OBJ_GETTER(Kotlin_boxByte, KByte value);
|
||||||
|
OBJ_GETTER(Kotlin_boxShort, KShort value);
|
||||||
|
OBJ_GETTER(Kotlin_boxInt, KInt value);
|
||||||
|
OBJ_GETTER(Kotlin_boxLong, KLong value);
|
||||||
|
OBJ_GETTER(Kotlin_boxUByte, KUByte value);
|
||||||
|
OBJ_GETTER(Kotlin_boxUShort, KUShort value);
|
||||||
|
OBJ_GETTER(Kotlin_boxUInt, KUInt value);
|
||||||
|
OBJ_GETTER(Kotlin_boxULong, KULong value);
|
||||||
|
OBJ_GETTER(Kotlin_boxFloat, KFloat value);
|
||||||
|
OBJ_GETTER(Kotlin_boxDouble, KDouble value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface NSNumber (NSNumberToKotlin) <ConvertibleToKotlin>
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@implementation NSNumber (NSNumberToKotlin)
|
||||||
|
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
|
||||||
|
const char* type = self.objCType;
|
||||||
|
|
||||||
|
// TODO: the code below makes some assumption on char, short, int and long sizes.
|
||||||
|
|
||||||
|
switch (type[0]) {
|
||||||
|
case 'c': RETURN_RESULT_OF(Kotlin_boxByte, self.charValue);
|
||||||
|
case 's': RETURN_RESULT_OF(Kotlin_boxShort, self.shortValue);
|
||||||
|
case 'i': RETURN_RESULT_OF(Kotlin_boxInt, self.intValue);
|
||||||
|
case 'q': RETURN_RESULT_OF(Kotlin_boxLong, self.longLongValue);
|
||||||
|
case 'C': RETURN_RESULT_OF(Kotlin_boxUByte, self.unsignedCharValue);
|
||||||
|
case 'S': RETURN_RESULT_OF(Kotlin_boxUShort, self.unsignedShortValue);
|
||||||
|
case 'I': RETURN_RESULT_OF(Kotlin_boxUInt, self.unsignedIntValue);
|
||||||
|
case 'Q': RETURN_RESULT_OF(Kotlin_boxULong, self.unsignedLongLongValue);
|
||||||
|
case 'f': RETURN_RESULT_OF(Kotlin_boxFloat, self.floatValue);
|
||||||
|
case 'd': RETURN_RESULT_OF(Kotlin_boxDouble, self.doubleValue);
|
||||||
|
|
||||||
|
default: RETURN_RESULT_OF(Kotlin_ObjCExport_convertUnmappedObjCObject, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@interface NSDecimalNumber (NSDecimalNumberToKotlin) <ConvertibleToKotlin>
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@implementation NSDecimalNumber (NSDecimalNumberToKotlin)
|
||||||
|
// Overrides [NSNumber toKotlin:] implementation.
|
||||||
|
-(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
|
||||||
|
RETURN_RESULT_OF(Kotlin_ObjCExport_convertUnmappedObjCObject, self);
|
||||||
|
}
|
||||||
|
@end;
|
||||||
|
|
||||||
|
static void checkLoadedOnce() {
|
||||||
|
Class marker = objc_allocateClassPair([NSObject class], "KotlinFrameworkLoadedOnceMarker", 0);
|
||||||
|
if (marker == nullptr) {
|
||||||
|
[NSException raise:NSGenericException
|
||||||
|
format:@"Only one Kotlin framework can be loaded currently"];
|
||||||
|
} else {
|
||||||
|
objc_registerClassPair(marker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void injectToRuntime() {
|
||||||
|
RuntimeCheck(Kotlin_ObjCExport_toKotlinSelector == nullptr, "runtime injected twice");
|
||||||
|
Kotlin_ObjCExport_toKotlinSelector = @selector(toKotlin:);
|
||||||
|
|
||||||
|
RuntimeCheck(Kotlin_ObjCExport_releaseAsAssociatedObjectSelector == nullptr, "runtime injected twice");
|
||||||
|
Kotlin_ObjCExport_releaseAsAssociatedObjectSelector = @selector(releaseAsAssociatedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // KONAN_OBJC_INTEROP
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if KONAN_OBJC_INTEROP
|
||||||
|
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#import <Foundation/NSObject.h>
|
||||||
|
#import "Memory.h"
|
||||||
|
#import "MemorySharedRefs.hpp"
|
||||||
|
#import "ObjCInteropUtilsPrivate.h"
|
||||||
|
|
||||||
|
// TODO: rework the interface to reduce the number of virtual calls
|
||||||
|
// in Kotlin_Interop_createKotlinObjectHolder and Kotlin_Interop_unwrapKotlinObjectHolder
|
||||||
|
@interface KotlinObjectHolder : NSObject
|
||||||
|
-(id)initWithRef:(KRef)ref;
|
||||||
|
-(KRef)ref;
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@implementation KotlinObjectHolder {
|
||||||
|
KRefSharedHolder refHolder;
|
||||||
|
};
|
||||||
|
|
||||||
|
-(id)initWithRef:(KRef)ref {
|
||||||
|
if (self = [super init]) {
|
||||||
|
refHolder.init(ref);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(KRef)ref {
|
||||||
|
return refHolder.ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)dealloc {
|
||||||
|
refHolder.dispose();
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end;
|
||||||
|
|
||||||
|
static id Kotlin_Interop_createKotlinObjectHolder(KRef any) {
|
||||||
|
if (any == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [[[KotlinObjectHolder alloc] initWithRef:any] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
static KRef Kotlin_Interop_unwrapKotlinObjectHolder(id holder) {
|
||||||
|
if (holder == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [((KotlinObjectHolder*)holder) ref];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used as an associated object for ObjCWeakReferenceImpl.
|
||||||
|
@interface KotlinObjCWeakReference : NSObject
|
||||||
|
@end;
|
||||||
|
|
||||||
|
// libobjc:
|
||||||
|
extern "C" {
|
||||||
|
id objc_loadWeakRetained(id *location);
|
||||||
|
id objc_storeWeak(id *location, id newObj);
|
||||||
|
void objc_destroyWeak(id *location);
|
||||||
|
void objc_release(id obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation KotlinObjCWeakReference {
|
||||||
|
@public id referred;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when removing Kotlin object.
|
||||||
|
-(void)releaseAsAssociatedObject {
|
||||||
|
objc_destroyWeak(&referred);
|
||||||
|
objc_release(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end;
|
||||||
|
|
||||||
|
extern "C" OBJ_GETTER(Kotlin_Interop_refFromObjC, id obj);
|
||||||
|
|
||||||
|
static OBJ_GETTER(Konan_ObjCInterop_getWeakReference, KRef ref) {
|
||||||
|
MetaObjHeader* meta = ref->meta_object();
|
||||||
|
KotlinObjCWeakReference* objcRef = (KotlinObjCWeakReference*)meta->associatedObject_;
|
||||||
|
|
||||||
|
id objcReferred = objc_loadWeakRetained(&objcRef->referred);
|
||||||
|
KRef result = Kotlin_Interop_refFromObjC(objcReferred, OBJ_RESULT);
|
||||||
|
objc_release(objcReferred);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Konan_ObjCInterop_initWeakReference(KRef ref, id objcPtr) {
|
||||||
|
MetaObjHeader* meta = ref->meta_object();
|
||||||
|
KotlinObjCWeakReference* objcRef = [KotlinObjCWeakReference new];
|
||||||
|
objc_storeWeak(&objcRef->referred, objcPtr);
|
||||||
|
meta->associatedObject_ = objcRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void injectToRuntime() {
|
||||||
|
RuntimeCheck(Kotlin_Interop_createKotlinObjectHolder_ptr == nullptr, "runtime injected twice");
|
||||||
|
Kotlin_Interop_createKotlinObjectHolder_ptr = &Kotlin_Interop_createKotlinObjectHolder;
|
||||||
|
|
||||||
|
RuntimeCheck(Kotlin_Interop_unwrapKotlinObjectHolder_ptr == nullptr, "runtime injected twice");
|
||||||
|
Kotlin_Interop_unwrapKotlinObjectHolder_ptr = &Kotlin_Interop_unwrapKotlinObjectHolder;
|
||||||
|
|
||||||
|
RuntimeCheck(Konan_ObjCInterop_getWeakReference_ptr == nullptr, "runtime injected twice");
|
||||||
|
Konan_ObjCInterop_getWeakReference_ptr = &Konan_ObjCInterop_getWeakReference;
|
||||||
|
|
||||||
|
RuntimeCheck(Konan_ObjCInterop_initWeakReference_ptr == nullptr, "runtime injected twice");
|
||||||
|
Konan_ObjCInterop_initWeakReference_ptr = &Konan_ObjCInterop_initWeakReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // KONAN_OBJC_INTEROP
|
||||||
Reference in New Issue
Block a user