From ad1b10cdb095e4c1f24a7b2acf19dbd7dbb19503 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Wed, 27 Jul 2022 12:14:48 +0200 Subject: [PATCH] Native: switch to "Native" thread state for some Obj-C runtime calls A lot of calls to Objective-C runtime are potentially blocking. This commit adds a number of thread state switches to ensure these Obj-C runtime calls happen in "Native" thread state. Also, remove a bunch of such functions from CallsChecker exclude list. --- kotlin-native/runtime/src/main/cpp/KString.cpp | 3 +++ kotlin-native/runtime/src/main/cpp/ObjCExport.mm | 10 ++++++++++ kotlin-native/runtime/src/main/cpp/ObjCInterop.mm | 2 ++ kotlin-native/runtime/src/mm/cpp/CallsChecker.cpp | 14 -------------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/kotlin-native/runtime/src/main/cpp/KString.cpp b/kotlin-native/runtime/src/main/cpp/KString.cpp index 5019aeb9692..5f7f1c41f3c 100644 --- a/kotlin-native/runtime/src/main/cpp/KString.cpp +++ b/kotlin-native/runtime/src/main/cpp/KString.cpp @@ -135,6 +135,9 @@ void DisposeCString(char* cstring) { } ObjHeader* CreatePermanentStringFromCString(const char* nullTerminatedUTF8) { + // Note: this function can be called in "Native" thread state. But this is fine: + // while it indeed manipulates Kotlin objects, it doesn't in fact access _Kotlin heap_, + // because the accessed object is off-heap, imitating permanent static objects. const char* end = nullTerminatedUTF8 + strlen(nullTerminatedUTF8); size_t count = utf8::with_replacement::utf16_length(nullTerminatedUTF8, end); size_t headerSize = alignUp(sizeof(ArrayHeader), alignof(char16_t)); diff --git a/kotlin-native/runtime/src/main/cpp/ObjCExport.mm b/kotlin-native/runtime/src/main/cpp/ObjCExport.mm index 70713e62c4d..8d65ac90027 100644 --- a/kotlin-native/runtime/src/main/cpp/ObjCExport.mm +++ b/kotlin-native/runtime/src/main/cpp/ObjCExport.mm @@ -121,6 +121,8 @@ extern "C" const TypeInfo* Kotlin_ObjCExport_getAssociatedTypeInfo(Class clazz) } static void setAssociatedTypeInfo(Class clazz, const TypeInfo* typeInfo) { + kotlin::NativeOrUnregisteredThreadGuard threadStateGuard(/* reentrant = */ true); + // Note: [NSValue valueWithPointer:] uses autorelease (without possibility to eliminate this at the call site), // so using alloc-init sequence to avoid this. NSValue* value = [[NSValue alloc] initWithBytes:&typeInfo objCType:@encode(void*)]; @@ -315,6 +317,8 @@ extern "C" void Kotlin_ObjCExport_initializeClass(Class clazz) { return; } + kotlin::NativeOrUnregisteredThreadGuard threadStateGuard(/* reentrant = */ true); + const TypeInfo* typeInfo = typeAdapter->kotlinTypeInfo; bool isClassForPackage = typeInfo == nullptr; if (!isClassForPackage) { @@ -379,6 +383,8 @@ static void Kotlin_ObjCExport_initializeImpl() { RuntimeCheck(Kotlin_ObjCExport_toKotlinSelector != nullptr, "unexpected initialization order"); RuntimeCheck(Kotlin_ObjCExport_releaseAsAssociatedObjectSelector != nullptr, "unexpected initialization order"); + kotlin::NativeOrUnregisteredThreadGuard threadStateGuard(/* reentrant = */ true); + initTypeAdapters(); SEL toKotlinSelector = Kotlin_ObjCExport_toKotlinSelector; @@ -865,6 +871,8 @@ static void throwIfCantBeOverridden(Class clazz, const KotlinToObjCMethodAdapter } static const TypeInfo* createTypeInfo(Class clazz, const TypeInfo* superType, const TypeInfo* fieldsInfo) { + kotlin::NativeOrUnregisteredThreadGuard threadStateGuard(/* reentrant = */ true); + std_support::unordered_set definedSelectors; addDefinedSelectors(clazz, definedSelectors); @@ -1053,6 +1061,8 @@ static void addVirtualAdapters(Class clazz, const ObjCTypeAdapter* typeAdapter) static Class createClass(const TypeInfo* typeInfo, Class superClass) { RuntimeAssert(typeInfo->superType_ != nullptr, ""); + kotlin::NativeOrUnregisteredThreadGuard threadStateGuard(/* reentrant = */ true); + int classIndex = (anonymousClassNextId++); std_support::string className = Kotlin_ObjCInterop_getUniquePrefix(); className += "_kobjcc"; diff --git a/kotlin-native/runtime/src/main/cpp/ObjCInterop.mm b/kotlin-native/runtime/src/main/cpp/ObjCInterop.mm index 5539c166200..49961417995 100644 --- a/kotlin-native/runtime/src/main/cpp/ObjCInterop.mm +++ b/kotlin-native/runtime/src/main/cpp/ObjCInterop.mm @@ -298,6 +298,8 @@ void* CreateKotlinObjCClass(const KotlinObjCClassInfo* info) { return createdClass; } + kotlin::NativeOrUnregisteredThreadGuard threadStateGuard(/* reentrant = */ true); + Class newClass = allocateClass(info); RuntimeAssert(newClass != nullptr, "Failed to allocate Objective-C class"); diff --git a/kotlin-native/runtime/src/mm/cpp/CallsChecker.cpp b/kotlin-native/runtime/src/mm/cpp/CallsChecker.cpp index 757d393327a..ffb0d87eb30 100644 --- a/kotlin-native/runtime/src/mm/cpp/CallsChecker.cpp +++ b/kotlin-native/runtime/src/mm/cpp/CallsChecker.cpp @@ -189,14 +189,6 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = { "CFStringGetCharacters", "CFStringGetLength", "_Block_object_assign", - "class_addIvar", - "class_addMethod", - "class_addProtocol", - "class_copyMethodList", - "class_copyProtocolList", - "class_getClassMethod", - "class_getInstanceMethod", - "class_getInstanceVariable", "class_getName", "class_getSuperclass", "class_isMetaClass", @@ -205,7 +197,6 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = { "method_getTypeEncoding", "objc_alloc", "objc_alloc_init", - "objc_allocateClassPair", "objc_autorelease", "objc_autoreleasePoolPush", "objc_autoreleaseReturnValue", @@ -213,18 +204,13 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = { "objc_getClass", "objc_getProtocol", "objc_lookUpClass", - "objc_registerClassPair", "objc_retain", "objc_retainAutoreleaseReturnValue", "objc_retainBlock", - "objc_setAssociatedObject", "objc_storeWeak", "object_getClass", "object_isClass", - "protocol_copyProtocolList", - "protocol_getMethodDescription", "protocol_getName", - "sel_registerName", "llvm.assume", "llvm.ceil.*",