Native: improve ObjCExport thread state switching

This commit is contained in:
Svyatoslav Scherbina
2021-07-07 13:53:27 +00:00
committed by Space
parent 1a27f91a98
commit 2d0dbf9729
3 changed files with 44 additions and 35 deletions
@@ -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.*",