Native: improve thread state switches for NSSet/NSDictionary adapters
^KT-54119
This commit is contained in:
committed by
Space
parent
1630386712
commit
39c73e25a4
@@ -1079,6 +1079,25 @@ __attribute__((swift_name("Bar")))
|
||||
@property (readonly) NSString *farewell __attribute__((swift_name("farewell")));
|
||||
@end
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("KT54119KotlinKey")))
|
||||
@interface KtKT54119KotlinKey : KtBase
|
||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||
@end
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("Kt54119Kt")))
|
||||
@interface KtKt54119Kt : KtBase
|
||||
+ (BOOL)callContainsSet:(NSSet<id> *)set __attribute__((swift_name("callContains(set:)")));
|
||||
+ (id _Nullable)callGetElementSet:(NSSet<id> *)set __attribute__((swift_name("callGetElement(set:)")));
|
||||
+ (BOOL)callContainsKeyMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callContainsKey(map:)")));
|
||||
+ (BOOL)callContainsValueMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callContainsValue(map:)")));
|
||||
+ (id _Nullable)callGetMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callGet(map:)")));
|
||||
+ (int32_t)callGetOrThrowConcurrentModificationMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callGetOrThrowConcurrentModification(map:)")));
|
||||
+ (BOOL)callContainsEntryMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callContainsEntry(map:)")));
|
||||
@end
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("LibraryKt")))
|
||||
@interface KtLibraryKt : KtBase
|
||||
|
||||
@@ -1014,6 +1014,25 @@ __attribute__((swift_name("Bar")))
|
||||
@property (readonly) NSString *farewell __attribute__((swift_name("farewell")));
|
||||
@end
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("KT54119KotlinKey")))
|
||||
@interface KtKT54119KotlinKey : KtBase
|
||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||
@end
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("Kt54119Kt")))
|
||||
@interface KtKt54119Kt : KtBase
|
||||
+ (BOOL)callContainsSet:(NSSet<id> *)set __attribute__((swift_name("callContains(set:)")));
|
||||
+ (id _Nullable)callGetElementSet:(NSSet<id> *)set __attribute__((swift_name("callGetElement(set:)")));
|
||||
+ (BOOL)callContainsKeyMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callContainsKey(map:)")));
|
||||
+ (BOOL)callContainsValueMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callContainsValue(map:)")));
|
||||
+ (id _Nullable)callGetMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callGet(map:)")));
|
||||
+ (int32_t)callGetOrThrowConcurrentModificationMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callGetOrThrowConcurrentModification(map:)")));
|
||||
+ (BOOL)callContainsEntryMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callContainsEntry(map:)")));
|
||||
@end
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("LibraryKt")))
|
||||
@interface KtLibraryKt : KtBase
|
||||
|
||||
@@ -1014,6 +1014,25 @@ __attribute__((swift_name("Bar")))
|
||||
@property (readonly) NSString *farewell __attribute__((swift_name("farewell")));
|
||||
@end
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("KT54119KotlinKey")))
|
||||
@interface KtKT54119KotlinKey : KtBase
|
||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||
@end
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("Kt54119Kt")))
|
||||
@interface KtKt54119Kt : KtBase
|
||||
+ (BOOL)callContainsSet:(NSSet<id> *)set __attribute__((swift_name("callContains(set:)")));
|
||||
+ (id _Nullable)callGetElementSet:(NSSet<id> *)set __attribute__((swift_name("callGetElement(set:)")));
|
||||
+ (BOOL)callContainsKeyMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callContainsKey(map:)")));
|
||||
+ (BOOL)callContainsValueMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callContainsValue(map:)")));
|
||||
+ (id _Nullable)callGetMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callGet(map:)")));
|
||||
+ (int32_t)callGetOrThrowConcurrentModificationMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callGetOrThrowConcurrentModification(map:)")));
|
||||
+ (BOOL)callContainsEntryMap:(NSDictionary<id, id> *)map __attribute__((swift_name("callContainsEntry(map:)")));
|
||||
@end
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("LibraryKt")))
|
||||
@interface KtLibraryKt : KtBase
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kt54119
|
||||
|
||||
class KT54119KotlinKey
|
||||
|
||||
private typealias Foo = KT54119KotlinKey
|
||||
|
||||
fun callContains(set: Set<*>) = set.contains(Foo())
|
||||
|
||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||
fun callGetElement(set: Set<*>) = (set as kotlin.native.internal.KonanSet<Any?>).getElement(Foo())
|
||||
|
||||
fun callContainsKey(map: Map<*, *>) = map.containsKey(Foo())
|
||||
|
||||
fun callContainsValue(map: Map<*, *>) = map.containsValue(Foo())
|
||||
|
||||
fun callGet(map: Map<*, *>) = map.get(Foo())
|
||||
|
||||
fun callGetOrThrowConcurrentModification(map: Map<*, *>) = map.hashCode() // calls getOrThrowConcurrentModification under the hood.
|
||||
fun callContainsEntry(map: Map<*, *>) = map.entries.contains(map.entries.first())
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import Kt
|
||||
|
||||
// See https://youtrack.jetbrains.com/issue/KT-54119/Native-runtime-assertion-failed-due-to-missing-thread-state-switch
|
||||
|
||||
private func testSetContains() throws {
|
||||
try assertFalse(Kt54119Kt.callContains(set: ["111"]))
|
||||
}
|
||||
|
||||
private func testSetGetElement() throws {
|
||||
try assertNil(Kt54119Kt.callGetElement(set: [222]))
|
||||
}
|
||||
|
||||
private func testMapContainsKey() throws {
|
||||
try assertFalse(Kt54119Kt.callContainsKey(map: ["abc" : "def"]))
|
||||
}
|
||||
|
||||
private func testMapContainsValue() throws {
|
||||
try assertFalse(Kt54119Kt.callContainsValue(map: [KT54119KotlinKey() : 1]))
|
||||
}
|
||||
|
||||
private func testMapGet() throws {
|
||||
try assertNil(Kt54119Kt.callGet(map: [0 : 0]))
|
||||
}
|
||||
|
||||
private func testMapGetOrThrowConcurrentModification() throws {
|
||||
Kt54119Kt.callGetOrThrowConcurrentModification(map: [KT54119KotlinKey() : 2])
|
||||
}
|
||||
|
||||
private func testMapContainsEntry() throws {
|
||||
try assertTrue(Kt54119Kt.callContainsEntry(map: [KT54119KotlinKey() : 3]))
|
||||
}
|
||||
|
||||
class Kt54119Tests : SimpleTestProvider {
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
test("testSetContains", testSetContains)
|
||||
test("testSetGetElement", testSetGetElement)
|
||||
test("testMapContainsKey", testMapContainsKey)
|
||||
test("testMapContainsValue", testMapContainsValue)
|
||||
test("testMapGet", testMapGet)
|
||||
test("testMapGetOrThrowConcurrentModification", testMapGetOrThrowConcurrentModification)
|
||||
test("testMapContainsEntry", testMapContainsEntry)
|
||||
}
|
||||
}
|
||||
@@ -119,16 +119,21 @@ extern "C" KInt Kotlin_NSSetAsKSet_getSize(KRef 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)];
|
||||
id objCElement = refToObjCOrNSNull(element);
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
return [set containsObject:objCElement];
|
||||
}
|
||||
|
||||
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)];
|
||||
id objCElement = refToObjCOrNSNull(element);
|
||||
id res;
|
||||
{
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
res = [set member:objCElement];
|
||||
}
|
||||
RETURN_RESULT_OF(refFromObjCOrNSNull, res);
|
||||
}
|
||||
|
||||
@@ -148,16 +153,17 @@ extern "C" KInt Kotlin_NSDictionaryAsKMap_getSize(KRef 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;
|
||||
id objCKey = refToObjCOrNSNull(key);
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
return [dict objectForKey:objCKey] != nullptr;
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsValue(KRef thiz, KRef value) {
|
||||
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
|
||||
id objCValue = refToObjCOrNSNull(value);
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
for (id key in dict) {
|
||||
if ([[dict objectForKey:key] isEqual:objCValue]) {
|
||||
return true;
|
||||
@@ -167,17 +173,25 @@ 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)];
|
||||
id objCKey = refToObjCOrNSNull(key);
|
||||
id value;
|
||||
{
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
value = [dict objectForKey:objCKey];
|
||||
}
|
||||
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)];
|
||||
id objCKey = refToObjCOrNSNull(key);
|
||||
id value;
|
||||
{
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
value = [dict objectForKey:objCKey];
|
||||
}
|
||||
if (value == nullptr) {
|
||||
Kotlin_ObjCExport_ThrowCollectionConcurrentModification();
|
||||
}
|
||||
@@ -185,10 +199,12 @@ 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)]];
|
||||
id objCValue = refToObjCOrNSNull(value);
|
||||
id objCKey = refToObjCOrNSNull(key);
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
return [objCValue isEqual:[dict objectForKey:objCKey]];
|
||||
}
|
||||
|
||||
NO_EXTERNAL_CALLS_CHECK
|
||||
|
||||
Reference in New Issue
Block a user