Native: improve ObjCExport thread state switching
This commit is contained in:
committed by
Space
parent
1a27f91a98
commit
2d0dbf9729
@@ -53,22 +53,35 @@ static inline KInt objCSizeToKotlinOrThrow(NSUInteger size) {
|
||||
|
||||
// Exported to ObjCExportUtils.kt:
|
||||
|
||||
// Note: a lot of functions below call Objective-C virtual methods of arbitrary classes
|
||||
// in Runnable thread state. Some these functions are marked with NO_EXTERNAL_CALLS_CHECK.
|
||||
// On the one hand, these calls aren't guaranteed to be fast, and also can call back to Kotlin.
|
||||
// Anything of this is harmful in Runnable state.
|
||||
// On the other hand, anything of this is unlikely to actually happen, and switching thread state
|
||||
// to Native might kill the performance, because these functions are just tiny wrappers for tiny functions.
|
||||
// So let's just ignore this for now, and deal with it later.
|
||||
// TODO: come up with a proper solution.
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" KInt Kotlin_NSArrayAsKList_getSize(KRef obj) {
|
||||
NSArray* array = (NSArray*) GetAssociatedObject(obj);
|
||||
return objCSizeToKotlinOrThrow([array count]);
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" OBJ_GETTER(Kotlin_NSArrayAsKList_get, KRef obj, KInt index) {
|
||||
NSArray* array = (NSArray*) GetAssociatedObject(obj);
|
||||
id element = [array objectAtIndex:index];
|
||||
RETURN_RESULT_OF(refFromObjCOrNSNull, element);
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" void Kotlin_NSMutableArrayAsKMutableList_add(KRef thiz, KInt index, KRef element) {
|
||||
NSMutableArray* mutableArray = (NSMutableArray*) GetAssociatedObject(thiz);
|
||||
[mutableArray insertObject:refToObjCOrNSNull(element) atIndex:index];
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" OBJ_GETTER(Kotlin_NSMutableArrayAsKMutableList_removeAt, KRef thiz, KInt index) {
|
||||
NSMutableArray* mutableArray = (NSMutableArray*) GetAssociatedObject(thiz);
|
||||
|
||||
@@ -78,6 +91,7 @@ extern "C" OBJ_GETTER(Kotlin_NSMutableArrayAsKMutableList_removeAt, KRef thiz, K
|
||||
return res;
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" OBJ_GETTER(Kotlin_NSMutableArrayAsKMutableList_set, KRef thiz, KInt index, KRef element) {
|
||||
NSMutableArray* mutableArray = (NSMutableArray*) GetAssociatedObject(thiz);
|
||||
|
||||
@@ -87,6 +101,7 @@ extern "C" OBJ_GETTER(Kotlin_NSMutableArrayAsKMutableList_set, KRef thiz, KInt i
|
||||
return res;
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" void Kotlin_NSEnumeratorAsKIterator_computeNext(KRef thiz) {
|
||||
NSEnumerator* enumerator = (NSEnumerator*) GetAssociatedObject(thiz);
|
||||
id next = [enumerator nextObject];
|
||||
@@ -98,16 +113,19 @@ extern "C" void Kotlin_NSEnumeratorAsKIterator_computeNext(KRef thiz) {
|
||||
}
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" KInt Kotlin_NSSetAsKSet_getSize(KRef thiz) {
|
||||
NSSet* set = (NSSet*) GetAssociatedObject(thiz);
|
||||
return objCSizeToKotlinOrThrow(set.count);
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" KBoolean Kotlin_NSSetAsKSet_contains(KRef thiz, KRef element) {
|
||||
NSSet* set = (NSSet*) GetAssociatedObject(thiz);
|
||||
return [set containsObject:refToObjCOrNSNull(element)];
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" OBJ_GETTER(Kotlin_NSSetAsKSet_getElement, KRef thiz, KRef element) {
|
||||
NSSet* set = (NSSet*) GetAssociatedObject(thiz);
|
||||
id res = [set member:refToObjCOrNSNull(element)];
|
||||
@@ -118,21 +136,25 @@ static inline OBJ_GETTER(CreateKIteratorFromNSEnumerator, NSEnumerator* enumerat
|
||||
RETURN_RESULT_OF(invokeAndAssociate, Kotlin_NSEnumeratorAsKIterator_create, objc_retain(enumerator));
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" OBJ_GETTER(Kotlin_NSSetAsKSet_iterator, KRef thiz) {
|
||||
NSSet* set = (NSSet*) GetAssociatedObject(thiz);
|
||||
RETURN_RESULT_OF(CreateKIteratorFromNSEnumerator, [set objectEnumerator]);
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" KInt Kotlin_NSDictionaryAsKMap_getSize(KRef thiz) {
|
||||
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
|
||||
return objCSizeToKotlinOrThrow(dict.count);
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsKey(KRef thiz, KRef key) {
|
||||
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
|
||||
return [dict objectForKey:refToObjCOrNSNull(key)] != nullptr;
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsValue(KRef thiz, KRef value) {
|
||||
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
|
||||
id objCValue = refToObjCOrNSNull(value);
|
||||
@@ -145,12 +167,14 @@ extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsValue(KRef thiz, KRef valu
|
||||
return false;
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_get, KRef thiz, KRef key) {
|
||||
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
|
||||
id value = [dict objectForKey:refToObjCOrNSNull(key)];
|
||||
RETURN_RESULT_OF(refFromObjCOrNSNull, value);
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_getOrThrowConcurrentModification, KRef thiz, KRef key) {
|
||||
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
|
||||
id value = [dict objectForKey:refToObjCOrNSNull(key)];
|
||||
@@ -161,16 +185,19 @@ extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_getOrThrowConcurrentModification
|
||||
RETURN_RESULT_OF(refFromObjCOrNSNull, value);
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsEntry(KRef thiz, KRef key, KRef value) {
|
||||
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
|
||||
return [refToObjCOrNSNull(value) isEqual:[dict objectForKey:refToObjCOrNSNull(key)]];
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_keyIterator, KRef thiz) {
|
||||
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
|
||||
RETURN_RESULT_OF(CreateKIteratorFromNSEnumerator, [dict keyEnumerator]);
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_valueIterator, KRef thiz) {
|
||||
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
|
||||
RETURN_RESULT_OF(CreateKIteratorFromNSEnumerator, [dict objectEnumerator]);
|
||||
|
||||
@@ -74,13 +74,18 @@ extern "C" id Kotlin_ObjCExport_ExceptionAsNSError(KRef exception, const TypeInf
|
||||
}
|
||||
|
||||
extern "C" id Kotlin_ObjCExport_WrapExceptionToNSError(KRef exception) {
|
||||
NSMutableDictionary<NSErrorUserInfoKey, id>* userInfo = [[NSMutableDictionary new] autorelease];
|
||||
userInfo[@"KotlinException"] = Kotlin_ObjCExport_refToObjC(exception);
|
||||
userInfo[@"KotlinExceptionOrigin"] = @(&kotlinExceptionOriginChar); // Support for different Kotlin runtimes loaded.
|
||||
|
||||
ObjHolder messageHolder;
|
||||
KRef message = Kotlin_Throwable_getMessage(exception, messageHolder.slot());
|
||||
NSString* description = Kotlin_Interop_CreateNSStringFromKString(message);
|
||||
|
||||
id exceptionObjCRef = Kotlin_ObjCExport_refToObjC(exception);
|
||||
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
|
||||
NSMutableDictionary<NSErrorUserInfoKey, id>* userInfo = [[NSMutableDictionary new] autorelease];
|
||||
userInfo[@"KotlinException"] = exceptionObjCRef;
|
||||
userInfo[@"KotlinExceptionOrigin"] = @(&kotlinExceptionOriginChar); // Support for different Kotlin runtimes loaded.
|
||||
|
||||
if (description != nullptr) {
|
||||
userInfo[NSLocalizedDescriptionKey] = description;
|
||||
}
|
||||
@@ -97,9 +102,12 @@ extern "C" OBJ_GETTER(Kotlin_ObjCExport_NSErrorAsExceptionImpl, KRef message, KR
|
||||
|
||||
extern "C" OBJ_GETTER(Kotlin_ObjCExport_NSErrorAsException, id error) {
|
||||
NSString* description;
|
||||
id wrappedKotlinException = nullptr;
|
||||
|
||||
NSError* e = (NSError*) error;
|
||||
if (e != nullptr) {
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
|
||||
auto userInfo = e.userInfo;
|
||||
if (userInfo != nullptr) {
|
||||
id kotlinException = userInfo[@"KotlinException"];
|
||||
@@ -107,7 +115,7 @@ extern "C" OBJ_GETTER(Kotlin_ObjCExport_NSErrorAsException, id error) {
|
||||
if (kotlinException != nullptr &&
|
||||
kotlinExceptionOrigin != nullptr && [kotlinExceptionOrigin isEqual:@(&kotlinExceptionOriginChar)]
|
||||
) {
|
||||
RETURN_RESULT_OF(Kotlin_ObjCExport_refFromObjC, kotlinException);
|
||||
wrappedKotlinException = kotlinException;
|
||||
}
|
||||
}
|
||||
description = e.localizedDescription;
|
||||
@@ -115,6 +123,10 @@ extern "C" OBJ_GETTER(Kotlin_ObjCExport_NSErrorAsException, id error) {
|
||||
description = nullptr;
|
||||
}
|
||||
|
||||
if (wrappedKotlinException != nullptr) {
|
||||
RETURN_RESULT_OF(Kotlin_ObjCExport_refFromObjC, wrappedKotlinException);
|
||||
}
|
||||
|
||||
ObjHolder messageHolder, errorHolder;
|
||||
KRef message = Kotlin_Interop_CreateKStringFromNSString(description, messageHolder.slot());
|
||||
KRef kotlinError = Kotlin_ObjCExport_refFromObjC(error, errorHolder.slot()); // TODO: a simple opaque wrapper would be enough.
|
||||
|
||||
@@ -141,7 +141,6 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = {
|
||||
"pthread_mutex_unlock",
|
||||
"pthread_self",
|
||||
|
||||
"+[NSError errorWithDomain:code:userInfo:]",
|
||||
"+[NSMethodSignature signatureWithObjCTypes:]",
|
||||
"+[NSNull null]",
|
||||
"+[NSObject allocWithZone:]",
|
||||
@@ -152,9 +151,6 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = {
|
||||
"+[NSString stringWithFormat:]",
|
||||
"+[NSString stringWithUTF8String:]",
|
||||
"+[NSValue valueWithPointer:]",
|
||||
"-[NSDictionary objectForKeyedSubscript:]",
|
||||
"-[NSError localizedDescription]",
|
||||
"-[NSError userInfo]",
|
||||
"-[NSException name]",
|
||||
"-[NSException reason]",
|
||||
"-[NSMethodSignature getArgumentTypeAtIndex:]",
|
||||
@@ -167,11 +163,6 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = {
|
||||
"-[NSPlaceholderString initWithBytes:length:encoding:]",
|
||||
"-[NSPlaceholderString initWithBytesNoCopy:length:encoding:freeWhenDone:]",
|
||||
"-[NSValue pointerValue]",
|
||||
"-[__NSArray0 count]",
|
||||
"-[__NSArrayI count]",
|
||||
"-[__NSArrayI objectAtIndex:]",
|
||||
"-[__NSArrayM count]",
|
||||
"-[__NSArrayM objectAtIndex:]",
|
||||
"-[__NSCFBoolean boolValue]",
|
||||
"-[__NSCFNumber doubleValue]",
|
||||
"-[__NSCFNumber floatValue]",
|
||||
@@ -179,9 +170,6 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = {
|
||||
"-[__NSCFNumber longLongValue]",
|
||||
"-[__NSCFNumber objCType]",
|
||||
"-[__NSCFString isEqual:]",
|
||||
"-[__NSDictionaryM setObject:forKeyedSubscript:]",
|
||||
"-[__NSFrozenDictionaryM objectForKeyedSubscript:]",
|
||||
"-[__SwiftNativeNSError userInfo]",
|
||||
"CFStringCreateCopy",
|
||||
"CFStringGetCharacters",
|
||||
"CFStringGetLength",
|
||||
@@ -221,24 +209,6 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = {
|
||||
"protocol_getName",
|
||||
"sel_registerName",
|
||||
|
||||
|
||||
// @objc Swift._ContiguousArrayStorage.count.getter : Swift.Int
|
||||
"$ss23_ContiguousArrayStorageC5countSivgTo",
|
||||
// @objc Swift.__SwiftDeferredNSArray.count.getter : Swift.Int
|
||||
"$ss22__SwiftDeferredNSArrayC5countSivgTo",
|
||||
// @objc Swift._ContiguousArrayStorage.objectAt(Swift.Int) -> Swift.Unmanaged<Swift.AnyObject>
|
||||
"$ss23_ContiguousArrayStorageC8objectAtys9UnmanagedVyyXlGSiFTo",
|
||||
// @objc Swift.__SwiftNativeNSArrayWithContiguousStorage.objectAt(Swift.Int) -> Swift.Unmanaged<Swift.AnyObject>
|
||||
"$ss41__SwiftNativeNSArrayWithContiguousStorageC8objectAtys9UnmanagedVyyXlGSiFTo",
|
||||
// @objc Swift.__EmptyDictionarySingleton.count.getter : Swift.Int
|
||||
"$ss26__EmptyDictionarySingletonC5countSivgTo",
|
||||
// @objc Swift._SwiftDeferredNSDictionary.count.getter : Swift.Int
|
||||
"$ss26_SwiftDeferredNSDictionaryC5countSivgTo",
|
||||
// @objc Swift._SwiftDeferredNSDictionary.keyEnumerator() -> Swift._NSEnumerator
|
||||
"$ss26_SwiftDeferredNSDictionaryC13keyEnumerators13_NSEnumerator_pyFTo",
|
||||
// @objc Swift._SwiftDictionaryNSEnumerator.nextObject() -> Swift.AnyObject?
|
||||
"$ss28_SwiftDictionaryNSEnumeratorC10nextObjectyXlSgyFTo",
|
||||
|
||||
"llvm.assume",
|
||||
"llvm.ceil.*",
|
||||
"llvm.copysign.*",
|
||||
|
||||
Reference in New Issue
Block a user