167 lines
5.1 KiB
Plaintext
167 lines
5.1 KiB
Plaintext
/*
|
|
* Copyright 2010-2022 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.
|
|
*/
|
|
|
|
#include "Natives.h"
|
|
|
|
#if KONAN_OBJC_INTEROP
|
|
|
|
#import <objc/runtime.h>
|
|
#import <CoreFoundation/CFString.h>
|
|
#import <Foundation/NSException.h>
|
|
#import <Foundation/NSString.h>
|
|
#import "Memory.h"
|
|
#import "ObjCInteropUtils.h"
|
|
#import "ObjCInteropUtilsPrivate.h"
|
|
|
|
namespace {
|
|
Class nsStringClass = nullptr;
|
|
|
|
Class getNSStringClass() {
|
|
Class result = nsStringClass;
|
|
if (result == nullptr) {
|
|
// Lookup dynamically to avoid direct reference to Foundation:
|
|
result = objc_getClass("NSString");
|
|
RuntimeAssert(result != nullptr, "NSString class not found");
|
|
nsStringClass = result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Note: using @"foo" string literals leads to linkage dependency on frameworks.
|
|
NSString* cStringToNS(const char* str) {
|
|
return [getNSStringClass() stringWithCString:str encoding:NSUTF8StringEncoding];
|
|
}
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
id Kotlin_ObjCExport_CreateRetainedNSStringFromKString(ObjHeader* str);
|
|
|
|
extern "C" id objc_autorelease(id self);
|
|
|
|
id Kotlin_Interop_CreateNSStringFromKString(ObjHeader* str) {
|
|
// Note: this function is just a bit specialized [Kotlin_Interop_refToObjC].
|
|
if (str == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (void* associatedObject = str->GetAssociatedObject()) {
|
|
return (id)associatedObject;
|
|
}
|
|
|
|
return objc_autorelease(Kotlin_ObjCExport_CreateRetainedNSStringFromKString(str));
|
|
}
|
|
|
|
OBJ_GETTER(Kotlin_Interop_CreateKStringFromNSString, NSString* str) {
|
|
if (str == nullptr) {
|
|
RETURN_OBJ(nullptr);
|
|
}
|
|
|
|
CFStringRef immutableCopyOrSameStr = CFStringCreateCopy(nullptr, (CFStringRef)str);
|
|
|
|
auto length = CFStringGetLength(immutableCopyOrSameStr);
|
|
CFRange range = {0, length};
|
|
ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, length, OBJ_RESULT)->array();
|
|
KChar* rawResult = CharArrayAddressOfElementAt(result, 0);
|
|
|
|
CFStringGetCharacters(immutableCopyOrSameStr, range, rawResult);
|
|
|
|
result->obj()->SetAssociatedObject((void*)immutableCopyOrSameStr);
|
|
|
|
RETURN_OBJ(result->obj());
|
|
}
|
|
|
|
// Note: this body is used for init methods with signatures differing from this;
|
|
// it is correct on arm64 and x86_64, because the body uses only the first two arguments which are fixed,
|
|
// and returns pointers.
|
|
id MissingInitImp(id self, SEL _cmd) {
|
|
const char* className = object_getClassName(self);
|
|
[self release]; // Since init methods receive ownership on the receiver.
|
|
|
|
// Lookup dynamically to avoid direct reference to Foundation:
|
|
Class nsExceptionClass = objc_getClass("NSException");
|
|
RuntimeAssert(nsExceptionClass != nullptr, "NSException class not found");
|
|
|
|
[nsExceptionClass raise:cStringToNS("Initializer is not implemented")
|
|
format:cStringToNS("%s is not implemented in %s"),
|
|
sel_getName(_cmd), className];
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// Initialized in [ObjCInteropUtilsClasses.mm].
|
|
id (*Kotlin_Interop_createKotlinObjectHolder_ptr)(KRef any) = nullptr;
|
|
KRef (*Kotlin_Interop_unwrapKotlinObjectHolder_ptr)(id holder) = nullptr;
|
|
|
|
id Kotlin_Interop_createKotlinObjectHolder(KRef any) {
|
|
return Kotlin_Interop_createKotlinObjectHolder_ptr(any);
|
|
}
|
|
|
|
KRef Kotlin_Interop_unwrapKotlinObjectHolder(id holder) {
|
|
return Kotlin_Interop_unwrapKotlinObjectHolder_ptr(holder);
|
|
}
|
|
|
|
KBoolean Kotlin_Interop_DoesObjectConformToProtocol(id obj, void* prot, KBoolean isMeta) {
|
|
BOOL objectIsClass = class_isMetaClass(object_getClass(obj));
|
|
if ((isMeta && !objectIsClass) || (!isMeta && objectIsClass)) return false;
|
|
// TODO: handle root classes properly.
|
|
|
|
return [((id<NSObject>)obj) conformsToProtocol:(Protocol*)prot];
|
|
}
|
|
|
|
KBoolean Kotlin_Interop_IsObjectKindOfClass(id obj, void* cls) {
|
|
return [((id<NSObject>)obj) isKindOfClass:(Class)cls];
|
|
}
|
|
|
|
OBJ_GETTER((*Konan_ObjCInterop_getWeakReference_ptr), KRef ref) = nullptr;
|
|
void (*Konan_ObjCInterop_initWeakReference_ptr)(KRef ref, id objcPtr) = nullptr;
|
|
|
|
OBJ_GETTER(Konan_ObjCInterop_getWeakReference, KRef ref) {
|
|
RETURN_RESULT_OF(Konan_ObjCInterop_getWeakReference_ptr, ref);
|
|
}
|
|
|
|
void Konan_ObjCInterop_initWeakReference(KRef ref, id objcPtr) {
|
|
Konan_ObjCInterop_initWeakReference_ptr(ref, objcPtr);
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
#else // KONAN_OBJC_INTEROP
|
|
|
|
extern "C" {
|
|
|
|
void* Kotlin_Interop_CreateNSStringFromKString(const ArrayHeader* str) {
|
|
RuntimeAssert(false, "Objective-C interop is disabled");
|
|
return nullptr;
|
|
}
|
|
|
|
OBJ_GETTER(Kotlin_Interop_CreateKStringFromNSString, void* str) {
|
|
RuntimeAssert(false, "Objective-C interop is disabled");
|
|
RETURN_OBJ(nullptr);
|
|
}
|
|
|
|
void* Kotlin_Interop_createKotlinObjectHolder(KRef any) {
|
|
RuntimeAssert(false, "Objective-C interop is disabled");
|
|
return nullptr;
|
|
}
|
|
|
|
KRef Kotlin_Interop_unwrapKotlinObjectHolder(void* holder) {
|
|
RuntimeAssert(false, "Objective-C interop is disabled");
|
|
return nullptr;
|
|
}
|
|
|
|
OBJ_GETTER(Konan_ObjCInterop_getWeakReference, KRef ref) {
|
|
RuntimeAssert(false, "Objective-C interop is disabled");
|
|
RETURN_OBJ(nullptr);
|
|
}
|
|
|
|
void Konan_ObjCInterop_initWeakReference(KRef ref, void* objcPtr) {
|
|
RuntimeAssert(false, "Objective-C interop is disabled");
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
#endif // KONAN_OBJC_INTEROP
|