diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt index c658e11e084..93ad4de3aba 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt @@ -62,6 +62,7 @@ private fun ObjCObjectBase.superInitCheck(superInitCallResult: ObjCObject?) { internal fun Any?.uncheckedCast(): T = @Suppress("UNCHECKED_CAST") (this as T) +// Note: if this is called for non-frozen object on a wrong worker, the program will terminate. @SymbolName("Kotlin_Interop_refFromObjC") external fun interpretObjCPointerOrNull(objcPtr: NativePtr): T? @@ -74,6 +75,7 @@ external fun Any?.objcPtr(): NativePtr @SymbolName("Kotlin_Interop_createKotlinObjectHolder") external fun createKotlinObjectHolder(any: Any?): NativePtr +// Note: if this is called for non-frozen underlying ref on a wrong worker, the program will terminate. inline fun unwrapKotlinObjectHolder(holder: Any?): T { return unwrapKotlinObjectHolderImpl(holder!!.objcPtr()) as T } diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 617d78c7e6e..7f18d802006 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -3967,6 +3967,16 @@ standaloneTest("interop_zlib") { goldValue = "Hello!\nHello!\n" } +standaloneTest("interop_objc_illegal_sharing") { + dependsOnPlatformLibs(it) + disabled = !isAppleTarget(project) + source = "interop/objc/illegal_sharing.kt" + expectedExitStatusChecker = { it != 0 } + outputChecker = { + it.startsWith("Before") && !it.contains("After") + } +} + dynamicTest("produce_dynamic") { disabled = (project.testTarget != null && project.testTarget != project.hostName) source = "produce_dynamic/simple/hello.kt" diff --git a/backend.native/tests/interop/objc/illegal_sharing.kt b/backend.native/tests/interop/objc/illegal_sharing.kt new file mode 100644 index 00000000000..12f7bfe0283 --- /dev/null +++ b/backend.native/tests/interop/objc/illegal_sharing.kt @@ -0,0 +1,30 @@ +import kotlin.native.concurrent.* +import kotlin.test.* +import platform.Foundation.* +import platform.darwin.NSObject + +fun Worker.runInWorker(block: () -> Unit) { + this.execute(TransferMode.SAFE, { block.freeze() }) { + it() + }.result +} + +private class NSObjectImpl : NSObject() { + var x = 111 +} + +// Also see counterpart in interop/objc/tests/sharing.kt +fun main() = withWorker { + val obj = NSObjectImpl() + val array: NSArray = NSMutableArray().apply { + addObject(obj) + } + + assertFalse(obj.isFrozen) + + println("Before") + runInWorker { + array.objectAtIndex(0) + } + println("After") +} diff --git a/backend.native/tests/interop/objc/tests/sharing.kt b/backend.native/tests/interop/objc/tests/sharing.kt index 3af3c312f14..0d72e58337c 100644 --- a/backend.native/tests/interop/objc/tests/sharing.kt +++ b/backend.native/tests/interop/objc/tests/sharing.kt @@ -7,18 +7,13 @@ private class NSObjectImpl : NSObject() { var x = 111 } +// Also see counterpart interop/objc/illegal_sharing.kt @Test fun testSharing() = withWorker { val obj = NSObjectImpl() val array = nsArrayOf(obj) assertFalse(obj.isFrozen) - runInWorker { - assertFailsWith { - array.objectAtIndex(0) - } - } - obj.x = 222 obj.freeze() assertTrue(obj.isFrozen) @@ -33,4 +28,4 @@ private class NSObjectImpl : NSObject() { assertEquals(222, obj.x) // TODO: test [obj release] etc. -} \ No newline at end of file +} diff --git a/runtime/src/main/cpp/Interop.cpp b/runtime/src/main/cpp/Interop.cpp index dea5b3415e5..4b6c2909110 100644 --- a/runtime/src/main/cpp/Interop.cpp +++ b/runtime/src/main/cpp/Interop.cpp @@ -39,7 +39,7 @@ void Kotlin_Interop_disposeStablePointer(KNativePtr pointer) { OBJ_GETTER(Kotlin_Interop_derefStablePointer, KNativePtr pointer) { KRefSharedHolder* holder = reinterpret_cast(pointer); - RETURN_OBJ(holder->ref()); + RETURN_OBJ(holder->ref()); } } diff --git a/runtime/src/main/cpp/MemorySharedRefs.cpp b/runtime/src/main/cpp/MemorySharedRefs.cpp index c60bb103b12..daad6c61d26 100644 --- a/runtime/src/main/cpp/MemorySharedRefs.cpp +++ b/runtime/src/main/cpp/MemorySharedRefs.cpp @@ -33,6 +33,44 @@ RUNTIME_NORETURN inline void throwIllegalSharingException(ObjHeader* object) { ThrowIllegalObjectSharingException(object->type_info(), object); } +RUNTIME_NORETURN inline void terminateWithIllegalSharingException(ObjHeader* object) { +#if KONAN_NO_EXCEPTIONS + // This will terminate. + throwIllegalSharingException(object); +#else + try { + throwIllegalSharingException(object); + } catch (...) { + // A trick to terminate with unhandled exception. This will print a stack trace + // and write to iOS crash log. + std::terminate(); + } +#endif +} + +template +bool ensureRefAccessible(ObjHeader* object, ForeignRefContext context) { + static_assert(errorPolicy != ErrorPolicy::kIgnore, "Must've been handled by specialization"); + + if (isForeignRefAccessible(object, context)) { + return true; + } + + switch (errorPolicy) { + case ErrorPolicy::kDefaultValue: + return false; + case ErrorPolicy::kThrow: + throwIllegalSharingException(object); + case ErrorPolicy::kTerminate: + terminateWithIllegalSharingException(object); + } +} + +template <> +bool ensureRefAccessible(ObjHeader* object, ForeignRefContext context) { + return true; +} + } // namespace void KRefSharedHolder::initLocal(ObjHeader* obj) { @@ -47,21 +85,20 @@ void KRefSharedHolder::init(ObjHeader* obj) { obj_ = obj; } +template ObjHeader* KRefSharedHolder::ref() const { - if (auto* result = refOrNull()) - return result; - - throwIllegalSharingException(obj_); -} - -ObjHeader* KRefSharedHolder::refOrNull() const { - if (!isRefAccessible()) { + if (!ensureRefAccessible(obj_, context_)) { return nullptr; } + AdoptReferenceFromSharedVariable(obj_); return obj_; } +template ObjHeader* KRefSharedHolder::ref() const; +template ObjHeader* KRefSharedHolder::ref() const; +template ObjHeader* KRefSharedHolder::ref() const; + void KRefSharedHolder::dispose() const { if (obj_ == nullptr) { // To handle the case when it is not initialized. See [KotlinMutableSet/Dictionary dealloc]. @@ -76,10 +113,6 @@ OBJ_GETTER0(KRefSharedHolder::describe) const { RETURN_RESULT_OF(DescribeObjectForDebugging, obj_->type_info(), obj_); } -bool KRefSharedHolder::isRefAccessible() const { - return isForeignRefAccessible(obj_, context_); -} - void BackRefFromAssociatedObject::initAndAddRef(ObjHeader* obj) { RuntimeAssert(obj != nullptr, "must not be null"); obj_ = obj; @@ -89,11 +122,14 @@ void BackRefFromAssociatedObject::initAndAddRef(ObjHeader* obj) { refCount = 1; } +template void BackRefFromAssociatedObject::addRef() { + static_assert(errorPolicy != ErrorPolicy::kDefaultValue, "Cannot use default return value here"); + if (atomicAdd(&refCount, 1) == 1) { // There are no references to the associated object itself, so Kotlin object is being passed from Kotlin, // and it is owned therefore. - ensureRefAccessible(); // TODO: consider removing explicit verification. + ensureRefAccessible(obj_, context_); // TODO: consider removing explicit verification. // Foreign reference has already been deinitialized (see [releaseRef]). // Create a new one: @@ -101,19 +137,31 @@ void BackRefFromAssociatedObject::addRef() { } } +template void BackRefFromAssociatedObject::addRef(); +template void BackRefFromAssociatedObject::addRef(); + +template bool BackRefFromAssociatedObject::tryAddRef() { + static_assert(errorPolicy != ErrorPolicy::kDefaultValue, "Cannot use default return value here"); + // Suboptimal but simple: - this->ensureRefAccessible(); - ObjHeader* obj = this->obj_; + ensureRefAccessible(obj_, context_); + + ObjHeader* obj = obj_; if (!TryAddHeapRef(obj)) return false; - this->addRef(); + RuntimeAssert(isForeignRefAccessible(obj_, context_), "Cannot be inaccessible because of the check above"); + // TODO: This is a very weird way to ask for "unsafe" addRef. + addRef(); ReleaseHeapRef(obj); // Balance TryAddHeapRef. // TODO: consider optimizing for non-shared objects. return true; } +template bool BackRefFromAssociatedObject::tryAddRef(); +template bool BackRefFromAssociatedObject::tryAddRef(); + void BackRefFromAssociatedObject::releaseRef() { ForeignRefContext context = context_; if (atomicAdd(&refCount, -1) == 0) { @@ -125,17 +173,19 @@ void BackRefFromAssociatedObject::releaseRef() { } } +template ObjHeader* BackRefFromAssociatedObject::ref() const { - ensureRefAccessible(); + if (!ensureRefAccessible(obj_, context_)) { + return nullptr; + } + AdoptReferenceFromSharedVariable(obj_); return obj_; } -void BackRefFromAssociatedObject::ensureRefAccessible() const { - if (!isForeignRefAccessible(obj_, context_)) { - throwIllegalSharingException(obj_); - } -} +template ObjHeader* BackRefFromAssociatedObject::ref() const; +template ObjHeader* BackRefFromAssociatedObject::ref() const; +template ObjHeader* BackRefFromAssociatedObject::ref() const; extern "C" { RUNTIME_NOTHROW void KRefSharedHolder_initLocal(KRefSharedHolder* holder, ObjHeader* obj) { @@ -150,7 +200,7 @@ RUNTIME_NOTHROW void KRefSharedHolder_dispose(const KRefSharedHolder* holder) { holder->dispose(); } -ObjHeader* KRefSharedHolder_ref(const KRefSharedHolder* holder) { - return holder->ref(); +RUNTIME_NOTHROW ObjHeader* KRefSharedHolder_ref(const KRefSharedHolder* holder) { + return holder->ref(); } } // extern "C" diff --git a/runtime/src/main/cpp/MemorySharedRefs.hpp b/runtime/src/main/cpp/MemorySharedRefs.hpp index a32b78e98c9..cc634b0d5ee 100644 --- a/runtime/src/main/cpp/MemorySharedRefs.hpp +++ b/runtime/src/main/cpp/MemorySharedRefs.hpp @@ -10,14 +10,23 @@ #include "Memory.h" +// TODO: Generalize for uses outside this file. +enum class ErrorPolicy { + kIgnore, // Ignore any errors. (i.e. unsafe mode) + kDefaultValue, // Return the default value from the function when an error happens. + kThrow, // Throw a Kotlin exception when an error happens. The exact exception is chosen by the callee. + kTerminate, // Terminate immediately when an error happens. +}; + class KRefSharedHolder { public: void initLocal(ObjHeader* obj); void init(ObjHeader* obj); + // Error if called from the wrong worker with non-frozen obj_. + template ObjHeader* ref() const; - ObjHeader* refOrNull() const; void dispose() const; @@ -26,8 +35,6 @@ class KRefSharedHolder { private: ObjHeader* obj_; ForeignRefContext context_; - - bool isRefAccessible() const; }; static_assert(std::is_trivially_destructible::value, @@ -37,12 +44,18 @@ class BackRefFromAssociatedObject { public: void initAndAddRef(ObjHeader* obj); + // Error if refCount is zero and it's called from the wrong worker with non-frozen obj_. + template void addRef(); + // Error if called from the wrong worker with non-frozen obj_. + template bool tryAddRef(); void releaseRef(); + // Error if called from the wrong worker with non-frozen obj_. + template ObjHeader* ref() const; inline bool permanent() const { @@ -53,8 +66,6 @@ class BackRefFromAssociatedObject { ObjHeader* obj_; ForeignRefContext context_; volatile int refCount; - - void ensureRefAccessible() const; }; static_assert(std::is_trivially_destructible::value, diff --git a/runtime/src/main/cpp/ObjCInterop.mm b/runtime/src/main/cpp/ObjCInterop.mm index f74a85433a3..95d67d160d6 100644 --- a/runtime/src/main/cpp/ObjCInterop.mm +++ b/runtime/src/main/cpp/ObjCInterop.mm @@ -69,7 +69,7 @@ BackRefFromAssociatedObject* getBackRef(id obj) { } OBJ_GETTER(toKotlinImp, id self, SEL _cmd) { - RETURN_OBJ(getBackRef(self)->ref()); + RETURN_OBJ(getBackRef(self)->ref()); } id allocWithZoneImp(Class self, SEL _cmd, void* zone) { @@ -89,7 +89,7 @@ id allocWithZoneImp(Class self, SEL _cmd, void* zone) { } id retainImp(id self, SEL _cmd) { - getBackRef(self)->addRef(); + getBackRef(self)->addRef(); return self; } @@ -99,7 +99,7 @@ BOOL _tryRetainImp(id self, SEL _cmd) { // loading a reference to such an object from Obj-C weak reference now fails on "wrong" thread // unless the object is frozen. try { - return getBackRef(self)->tryAddRef(); + return getBackRef(self)->tryAddRef(); } catch (ExceptionObjHolder& e) { // TODO: check for IncorrectDereferenceException and possible weak property access // Cannot use SourceInfo here, because CoreSymbolication framework (CSSymbolOwnerGetSymbolWithAddress) diff --git a/runtime/src/main/cpp/WorkerBoundReference.cpp b/runtime/src/main/cpp/WorkerBoundReference.cpp index bc9b3a24259..2399f11e136 100644 --- a/runtime/src/main/cpp/WorkerBoundReference.cpp +++ b/runtime/src/main/cpp/WorkerBoundReference.cpp @@ -38,7 +38,7 @@ KNativePtr Kotlin_WorkerBoundReference_create(KRef value) { } OBJ_GETTER(Kotlin_WorkerBoundReference_deref, KNativePtr holder) { - RETURN_OBJ(reinterpret_cast(holder)->refOrNull()); + RETURN_OBJ(reinterpret_cast(holder)->ref()); } OBJ_GETTER(Kotlin_WorkerBoundReference_describe, KNativePtr holder) { diff --git a/runtime/src/objc/cpp/ObjCExportClasses.mm b/runtime/src/objc/cpp/ObjCExportClasses.mm index 51c0afede4a..cdadd6dac97 100644 --- a/runtime/src/objc/cpp/ObjCExportClasses.mm +++ b/runtime/src/objc/cpp/ObjCExportClasses.mm @@ -36,12 +36,16 @@ extern "C" id objc_autoreleaseReturnValue(id self); static void injectToRuntime(); +// Note: `KotlinBase`'s `toKotlin` and `_tryRetain` methods will terminate if +// called with non-frozen object on a wrong worker. `retain` will also terminate +// in these conditions if backref's refCount is zero. + @implementation KotlinBase { BackRefFromAssociatedObject refHolder; } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(refHolder.ref()); + RETURN_OBJ(refHolder.ref()); } +(void)load { @@ -103,7 +107,7 @@ static void injectToRuntime(); if (refHolder.permanent()) { // TODO: consider storing `isPermanent` to self field. [super retain]; } else { - refHolder.addRef(); + refHolder.addRef(); } return self; } @@ -112,7 +116,7 @@ static void injectToRuntime(); if (refHolder.permanent()) { return [super _tryRetain]; } else { - return refHolder.tryAddRef(); + return refHolder.tryAddRef(); } } diff --git a/runtime/src/objc/cpp/ObjCExportCollections.mm b/runtime/src/objc/cpp/ObjCExportCollections.mm index 7ac5afc0b4d..50f400f1322 100644 --- a/runtime/src/objc/cpp/ObjCExportCollections.mm +++ b/runtime/src/objc/cpp/ObjCExportCollections.mm @@ -81,6 +81,9 @@ static inline KInt objCIndexToKotlinOrThrow(NSUInteger index) { return index; } +// Note: collections can only be iterated on and converted to Kotlin representation +// when they are either frozen or if they are called on the worker that created them. + @interface NSArray (NSArrayToKotlin) @end; @@ -155,7 +158,7 @@ static inline KInt objCIndexToKotlinOrThrow(NSUInteger index) { } - (id)nextObject { - KRef iterator = iteratorHolder.ref(); + KRef iterator = iteratorHolder.ref(); if (Kotlin_Iterator_hasNext(iterator)) { ObjHolder holder; return refToObjCOrNSNull(Kotlin_Iterator_next(iterator, holder.slot())); @@ -184,17 +187,17 @@ static inline KInt objCIndexToKotlinOrThrow(NSUInteger index) { } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(listHolder.ref()); + RETURN_OBJ(listHolder.ref()); } -(id)objectAtIndex:(NSUInteger)index { ObjHolder kotlinValueHolder; - KRef kotlinValue = Kotlin_List_get(listHolder.ref(), index, kotlinValueHolder.slot()); + KRef kotlinValue = Kotlin_List_get(listHolder.ref(), index, kotlinValueHolder.slot()); return refToObjCOrNSNull(kotlinValue); } -(NSUInteger)count { - return Kotlin_Collection_getSize(listHolder.ref()); + return Kotlin_Collection_getSize(listHolder.ref()); } @end; @@ -218,42 +221,42 @@ static inline KInt objCIndexToKotlinOrThrow(NSUInteger index) { } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(listHolder.ref()); + RETURN_OBJ(listHolder.ref()); } -(id)objectAtIndex:(NSUInteger)index { ObjHolder kotlinValueHolder; - KRef kotlinValue = Kotlin_List_get(listHolder.ref(), index, kotlinValueHolder.slot()); + KRef kotlinValue = Kotlin_List_get(listHolder.ref(), index, kotlinValueHolder.slot()); return refToObjCOrNSNull(kotlinValue); } -(NSUInteger)count { - return Kotlin_Collection_getSize(listHolder.ref()); + return Kotlin_Collection_getSize(listHolder.ref()); } - (void)insertObject:(id)anObject atIndex:(NSUInteger)index { ObjHolder holder; KRef kotlinObject = refFromObjCOrNSNull(anObject, holder.slot()); - Kotlin_MutableList_addObjectAtIndex(listHolder.ref(), objCIndexToKotlinOrThrow(index), kotlinObject); + Kotlin_MutableList_addObjectAtIndex(listHolder.ref(), objCIndexToKotlinOrThrow(index), kotlinObject); } - (void)removeObjectAtIndex:(NSUInteger)index { - Kotlin_MutableList_removeObjectAtIndex(listHolder.ref(), objCIndexToKotlinOrThrow(index)); + Kotlin_MutableList_removeObjectAtIndex(listHolder.ref(), objCIndexToKotlinOrThrow(index)); } - (void)addObject:(id)anObject { ObjHolder holder; - Kotlin_MutableCollection_addObject(listHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); + Kotlin_MutableCollection_addObject(listHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); } - (void)removeLastObject { - Kotlin_MutableList_removeLastObject(listHolder.ref()); + Kotlin_MutableList_removeLastObject(listHolder.ref()); } - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { ObjHolder holder; KRef kotlinObject = refFromObjCOrNSNull(anObject, holder.slot()); - Kotlin_MutableList_setObject(listHolder.ref(), objCIndexToKotlinOrThrow(index), kotlinObject); + Kotlin_MutableList_setObject(listHolder.ref(), objCIndexToKotlinOrThrow(index), kotlinObject); } @end; @@ -291,26 +294,26 @@ static inline id KSet_getElement(KRef set, id object) { } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(setHolder.ref()); + RETURN_OBJ(setHolder.ref()); } -(NSUInteger) count { - return Kotlin_Collection_getSize(setHolder.ref()); + return Kotlin_Collection_getSize(setHolder.ref()); } - (id)member:(id)object { - return KSet_getElement(setHolder.ref(), object); + return KSet_getElement(setHolder.ref(), object); } // Not mandatory, just an optimization: - (BOOL)containsObject:(id)anObject { ObjHolder holder; - return Kotlin_Set_contains(setHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); + return Kotlin_Set_contains(setHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); } - (NSEnumerator*)objectEnumerator { ObjHolder holder; - return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref(), holder.slot())]; + return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref(), holder.slot())]; } @end; @@ -375,36 +378,36 @@ static inline id KSet_getElement(KRef set, id object) { } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(setHolder.ref()); + RETURN_OBJ(setHolder.ref()); } -(NSUInteger) count { - return Kotlin_Collection_getSize(setHolder.ref()); + return Kotlin_Collection_getSize(setHolder.ref()); } - (id)member:(id)object { - return KSet_getElement(setHolder.ref(), object); + return KSet_getElement(setHolder.ref(), object); } // Not mandatory, just an optimization: - (BOOL)containsObject:(id)anObject { ObjHolder holder; - return Kotlin_Set_contains(setHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); + return Kotlin_Set_contains(setHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); } - (NSEnumerator*)objectEnumerator { ObjHolder holder; - return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref(), holder.slot())]; + return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref(), holder.slot())]; } - (void)addObject:(id)object { ObjHolder holder; - Kotlin_MutableCollection_addObject(setHolder.ref(), refFromObjCOrNSNull(object, holder.slot())); + Kotlin_MutableCollection_addObject(setHolder.ref(), refFromObjCOrNSNull(object, holder.slot())); } - (void)removeObject:(id)object { ObjHolder holder; - Kotlin_MutableCollection_removeObject(setHolder.ref(), refFromObjCOrNSNull(object, holder.slot())); + Kotlin_MutableCollection_removeObject(setHolder.ref(), refFromObjCOrNSNull(object, holder.slot())); } @end; @@ -441,23 +444,23 @@ static inline id KMap_get(KRef map, id aKey) { } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(mapHolder.ref()); + RETURN_OBJ(mapHolder.ref()); } // According to documentation, initWithObjects:forKeys:count: is required to be overridden when subclassing. // But that doesn't make any sense, since this class can't be arbitrary initialized. -(NSUInteger) count { - return Kotlin_Map_getSize(mapHolder.ref()); + return Kotlin_Map_getSize(mapHolder.ref()); } - (id)objectForKey:(id)aKey { - return KMap_get(mapHolder.ref(), aKey); + return KMap_get(mapHolder.ref(), aKey); } - (NSEnumerator *)keyEnumerator { ObjHolder holder; - return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref(), holder.slot())]; + return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref(), holder.slot())]; } @end; @@ -512,20 +515,20 @@ static inline id KMap_get(KRef map, id aKey) { } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(mapHolder.ref()); + RETURN_OBJ(mapHolder.ref()); } -(NSUInteger) count { - return Kotlin_Map_getSize(mapHolder.ref()); + return Kotlin_Map_getSize(mapHolder.ref()); } - (id)objectForKey:(id)aKey { - return KMap_get(mapHolder.ref(), aKey); + return KMap_get(mapHolder.ref(), aKey); } - (NSEnumerator *)keyEnumerator { ObjHolder holder; - return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref(), holder.slot())]; + return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref(), holder.slot())]; } - (void)setObject:(id)anObject forKey:(id)aKey { @@ -537,14 +540,14 @@ static inline id KMap_get(KRef map, id aKey) { KRef kotlinValue = refFromObjCOrNSNull(anObject, valueHolder.slot()); - Kotlin_MutableMap_set(mapHolder.ref(), kotlinKey, kotlinValue); + Kotlin_MutableMap_set(mapHolder.ref(), kotlinKey, kotlinValue); } - (void)removeObjectForKey:(id)aKey { ObjHolder holder; KRef kotlinKey = refFromObjCOrNSNull(aKey, holder.slot()); - Kotlin_MutableMap_remove(mapHolder.ref(), kotlinKey); + Kotlin_MutableMap_remove(mapHolder.ref(), kotlinKey); } @end; @@ -584,4 +587,4 @@ extern "C" id Kotlin_Interop_CreateKotlinMutableDictonaryFromKMap(KRef obj) { return [[[KotlinMutableDictionary alloc] initWithKMap:obj] autorelease]; } -#endif // KONAN_OBJC_INTEROP \ No newline at end of file +#endif // KONAN_OBJC_INTEROP diff --git a/runtime/src/objc/cpp/ObjCInteropUtilsClasses.mm b/runtime/src/objc/cpp/ObjCInteropUtilsClasses.mm index 796bc8c67ea..51054b85d21 100644 --- a/runtime/src/objc/cpp/ObjCInteropUtilsClasses.mm +++ b/runtime/src/objc/cpp/ObjCInteropUtilsClasses.mm @@ -30,7 +30,7 @@ } -(KRef)ref { - return refHolder.ref(); + return refHolder.ref(); } -(void)dealloc {