Do not use Kotlin exceptions from MemorySharedRefs in objc context (#4184)

This commit is contained in:
Alexander Shabalin
2020-06-22 15:29:10 +03:00
committed by GitHub
parent 1ba353291b
commit 3445de9c38
12 changed files with 185 additions and 80 deletions
@@ -62,6 +62,7 @@ private fun ObjCObjectBase.superInitCheck(superInitCallResult: ObjCObject?) {
internal fun <T : Any?> Any?.uncheckedCast(): T = @Suppress("UNCHECKED_CAST") (this as T) internal fun <T : Any?> 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") @SymbolName("Kotlin_Interop_refFromObjC")
external fun <T> interpretObjCPointerOrNull(objcPtr: NativePtr): T? external fun <T> interpretObjCPointerOrNull(objcPtr: NativePtr): T?
@@ -74,6 +75,7 @@ external fun Any?.objcPtr(): NativePtr
@SymbolName("Kotlin_Interop_createKotlinObjectHolder") @SymbolName("Kotlin_Interop_createKotlinObjectHolder")
external fun createKotlinObjectHolder(any: Any?): NativePtr 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 <reified T : Any> unwrapKotlinObjectHolder(holder: Any?): T { inline fun <reified T : Any> unwrapKotlinObjectHolder(holder: Any?): T {
return unwrapKotlinObjectHolderImpl(holder!!.objcPtr()) as T return unwrapKotlinObjectHolderImpl(holder!!.objcPtr()) as T
} }
+10
View File
@@ -3967,6 +3967,16 @@ standaloneTest("interop_zlib") {
goldValue = "Hello!\nHello!\n" 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") { dynamicTest("produce_dynamic") {
disabled = (project.testTarget != null && project.testTarget != project.hostName) disabled = (project.testTarget != null && project.testTarget != project.hostName)
source = "produce_dynamic/simple/hello.kt" source = "produce_dynamic/simple/hello.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")
}
@@ -7,18 +7,13 @@ private class NSObjectImpl : NSObject() {
var x = 111 var x = 111
} }
// Also see counterpart interop/objc/illegal_sharing.kt
@Test fun testSharing() = withWorker { @Test fun testSharing() = withWorker {
val obj = NSObjectImpl() val obj = NSObjectImpl()
val array = nsArrayOf(obj) val array = nsArrayOf(obj)
assertFalse(obj.isFrozen) assertFalse(obj.isFrozen)
runInWorker {
assertFailsWith<IncorrectDereferenceException> {
array.objectAtIndex(0)
}
}
obj.x = 222 obj.x = 222
obj.freeze() obj.freeze()
assertTrue(obj.isFrozen) assertTrue(obj.isFrozen)
@@ -33,4 +28,4 @@ private class NSObjectImpl : NSObject() {
assertEquals(222, obj.x) assertEquals(222, obj.x)
// TODO: test [obj release] etc. // TODO: test [obj release] etc.
} }
+1 -1
View File
@@ -39,7 +39,7 @@ void Kotlin_Interop_disposeStablePointer(KNativePtr pointer) {
OBJ_GETTER(Kotlin_Interop_derefStablePointer, KNativePtr pointer) { OBJ_GETTER(Kotlin_Interop_derefStablePointer, KNativePtr pointer) {
KRefSharedHolder* holder = reinterpret_cast<KRefSharedHolder*>(pointer); KRefSharedHolder* holder = reinterpret_cast<KRefSharedHolder*>(pointer);
RETURN_OBJ(holder->ref()); RETURN_OBJ(holder->ref<ErrorPolicy::kThrow>());
} }
} }
+74 -24
View File
@@ -33,6 +33,44 @@ RUNTIME_NORETURN inline void throwIllegalSharingException(ObjHeader* object) {
ThrowIllegalObjectSharingException(object->type_info(), 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 <ErrorPolicy errorPolicy>
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<ErrorPolicy::kIgnore>(ObjHeader* object, ForeignRefContext context) {
return true;
}
} // namespace } // namespace
void KRefSharedHolder::initLocal(ObjHeader* obj) { void KRefSharedHolder::initLocal(ObjHeader* obj) {
@@ -47,21 +85,20 @@ void KRefSharedHolder::init(ObjHeader* obj) {
obj_ = obj; obj_ = obj;
} }
template <ErrorPolicy errorPolicy>
ObjHeader* KRefSharedHolder::ref() const { ObjHeader* KRefSharedHolder::ref() const {
if (auto* result = refOrNull()) if (!ensureRefAccessible<errorPolicy>(obj_, context_)) {
return result;
throwIllegalSharingException(obj_);
}
ObjHeader* KRefSharedHolder::refOrNull() const {
if (!isRefAccessible()) {
return nullptr; return nullptr;
} }
AdoptReferenceFromSharedVariable(obj_); AdoptReferenceFromSharedVariable(obj_);
return obj_; return obj_;
} }
template ObjHeader* KRefSharedHolder::ref<ErrorPolicy::kDefaultValue>() const;
template ObjHeader* KRefSharedHolder::ref<ErrorPolicy::kThrow>() const;
template ObjHeader* KRefSharedHolder::ref<ErrorPolicy::kTerminate>() const;
void KRefSharedHolder::dispose() const { void KRefSharedHolder::dispose() const {
if (obj_ == nullptr) { if (obj_ == nullptr) {
// To handle the case when it is not initialized. See [KotlinMutableSet/Dictionary dealloc]. // 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_); RETURN_RESULT_OF(DescribeObjectForDebugging, obj_->type_info(), obj_);
} }
bool KRefSharedHolder::isRefAccessible() const {
return isForeignRefAccessible(obj_, context_);
}
void BackRefFromAssociatedObject::initAndAddRef(ObjHeader* obj) { void BackRefFromAssociatedObject::initAndAddRef(ObjHeader* obj) {
RuntimeAssert(obj != nullptr, "must not be null"); RuntimeAssert(obj != nullptr, "must not be null");
obj_ = obj; obj_ = obj;
@@ -89,11 +122,14 @@ void BackRefFromAssociatedObject::initAndAddRef(ObjHeader* obj) {
refCount = 1; refCount = 1;
} }
template <ErrorPolicy errorPolicy>
void BackRefFromAssociatedObject::addRef() { void BackRefFromAssociatedObject::addRef() {
static_assert(errorPolicy != ErrorPolicy::kDefaultValue, "Cannot use default return value here");
if (atomicAdd(&refCount, 1) == 1) { if (atomicAdd(&refCount, 1) == 1) {
// There are no references to the associated object itself, so Kotlin object is being passed from Kotlin, // There are no references to the associated object itself, so Kotlin object is being passed from Kotlin,
// and it is owned therefore. // and it is owned therefore.
ensureRefAccessible(); // TODO: consider removing explicit verification. ensureRefAccessible<errorPolicy>(obj_, context_); // TODO: consider removing explicit verification.
// Foreign reference has already been deinitialized (see [releaseRef]). // Foreign reference has already been deinitialized (see [releaseRef]).
// Create a new one: // Create a new one:
@@ -101,19 +137,31 @@ void BackRefFromAssociatedObject::addRef() {
} }
} }
template void BackRefFromAssociatedObject::addRef<ErrorPolicy::kThrow>();
template void BackRefFromAssociatedObject::addRef<ErrorPolicy::kTerminate>();
template <ErrorPolicy errorPolicy>
bool BackRefFromAssociatedObject::tryAddRef() { bool BackRefFromAssociatedObject::tryAddRef() {
static_assert(errorPolicy != ErrorPolicy::kDefaultValue, "Cannot use default return value here");
// Suboptimal but simple: // Suboptimal but simple:
this->ensureRefAccessible(); ensureRefAccessible<errorPolicy>(obj_, context_);
ObjHeader* obj = this->obj_;
ObjHeader* obj = obj_;
if (!TryAddHeapRef(obj)) return false; 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<ErrorPolicy::kIgnore>();
ReleaseHeapRef(obj); // Balance TryAddHeapRef. ReleaseHeapRef(obj); // Balance TryAddHeapRef.
// TODO: consider optimizing for non-shared objects. // TODO: consider optimizing for non-shared objects.
return true; return true;
} }
template bool BackRefFromAssociatedObject::tryAddRef<ErrorPolicy::kThrow>();
template bool BackRefFromAssociatedObject::tryAddRef<ErrorPolicy::kTerminate>();
void BackRefFromAssociatedObject::releaseRef() { void BackRefFromAssociatedObject::releaseRef() {
ForeignRefContext context = context_; ForeignRefContext context = context_;
if (atomicAdd(&refCount, -1) == 0) { if (atomicAdd(&refCount, -1) == 0) {
@@ -125,17 +173,19 @@ void BackRefFromAssociatedObject::releaseRef() {
} }
} }
template <ErrorPolicy errorPolicy>
ObjHeader* BackRefFromAssociatedObject::ref() const { ObjHeader* BackRefFromAssociatedObject::ref() const {
ensureRefAccessible(); if (!ensureRefAccessible<errorPolicy>(obj_, context_)) {
return nullptr;
}
AdoptReferenceFromSharedVariable(obj_); AdoptReferenceFromSharedVariable(obj_);
return obj_; return obj_;
} }
void BackRefFromAssociatedObject::ensureRefAccessible() const { template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kDefaultValue>() const;
if (!isForeignRefAccessible(obj_, context_)) { template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kThrow>() const;
throwIllegalSharingException(obj_); template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kTerminate>() const;
}
}
extern "C" { extern "C" {
RUNTIME_NOTHROW void KRefSharedHolder_initLocal(KRefSharedHolder* holder, ObjHeader* obj) { RUNTIME_NOTHROW void KRefSharedHolder_initLocal(KRefSharedHolder* holder, ObjHeader* obj) {
@@ -150,7 +200,7 @@ RUNTIME_NOTHROW void KRefSharedHolder_dispose(const KRefSharedHolder* holder) {
holder->dispose(); holder->dispose();
} }
ObjHeader* KRefSharedHolder_ref(const KRefSharedHolder* holder) { RUNTIME_NOTHROW ObjHeader* KRefSharedHolder_ref(const KRefSharedHolder* holder) {
return holder->ref(); return holder->ref<ErrorPolicy::kTerminate>();
} }
} // extern "C" } // extern "C"
+16 -5
View File
@@ -10,14 +10,23 @@
#include "Memory.h" #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 { class KRefSharedHolder {
public: public:
void initLocal(ObjHeader* obj); void initLocal(ObjHeader* obj);
void init(ObjHeader* obj); void init(ObjHeader* obj);
// Error if called from the wrong worker with non-frozen obj_.
template <ErrorPolicy errorPolicy>
ObjHeader* ref() const; ObjHeader* ref() const;
ObjHeader* refOrNull() const;
void dispose() const; void dispose() const;
@@ -26,8 +35,6 @@ class KRefSharedHolder {
private: private:
ObjHeader* obj_; ObjHeader* obj_;
ForeignRefContext context_; ForeignRefContext context_;
bool isRefAccessible() const;
}; };
static_assert(std::is_trivially_destructible<KRefSharedHolder>::value, static_assert(std::is_trivially_destructible<KRefSharedHolder>::value,
@@ -37,12 +44,18 @@ class BackRefFromAssociatedObject {
public: public:
void initAndAddRef(ObjHeader* obj); void initAndAddRef(ObjHeader* obj);
// Error if refCount is zero and it's called from the wrong worker with non-frozen obj_.
template <ErrorPolicy errorPolicy>
void addRef(); void addRef();
// Error if called from the wrong worker with non-frozen obj_.
template <ErrorPolicy errorPolicy>
bool tryAddRef(); bool tryAddRef();
void releaseRef(); void releaseRef();
// Error if called from the wrong worker with non-frozen obj_.
template <ErrorPolicy errorPolicy>
ObjHeader* ref() const; ObjHeader* ref() const;
inline bool permanent() const { inline bool permanent() const {
@@ -53,8 +66,6 @@ class BackRefFromAssociatedObject {
ObjHeader* obj_; ObjHeader* obj_;
ForeignRefContext context_; ForeignRefContext context_;
volatile int refCount; volatile int refCount;
void ensureRefAccessible() const;
}; };
static_assert(std::is_trivially_destructible<BackRefFromAssociatedObject>::value, static_assert(std::is_trivially_destructible<BackRefFromAssociatedObject>::value,
+3 -3
View File
@@ -69,7 +69,7 @@ BackRefFromAssociatedObject* getBackRef(id obj) {
} }
OBJ_GETTER(toKotlinImp, id self, SEL _cmd) { OBJ_GETTER(toKotlinImp, id self, SEL _cmd) {
RETURN_OBJ(getBackRef(self)->ref()); RETURN_OBJ(getBackRef(self)->ref<ErrorPolicy::kTerminate>());
} }
id allocWithZoneImp(Class self, SEL _cmd, void* zone) { 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) { id retainImp(id self, SEL _cmd) {
getBackRef(self)->addRef(); getBackRef(self)->addRef<ErrorPolicy::kTerminate>();
return self; 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 // loading a reference to such an object from Obj-C weak reference now fails on "wrong" thread
// unless the object is frozen. // unless the object is frozen.
try { try {
return getBackRef(self)->tryAddRef(); return getBackRef(self)->tryAddRef<ErrorPolicy::kThrow>();
} catch (ExceptionObjHolder& e) { } catch (ExceptionObjHolder& e) {
// TODO: check for IncorrectDereferenceException and possible weak property access // TODO: check for IncorrectDereferenceException and possible weak property access
// Cannot use SourceInfo here, because CoreSymbolication framework (CSSymbolOwnerGetSymbolWithAddress) // Cannot use SourceInfo here, because CoreSymbolication framework (CSSymbolOwnerGetSymbolWithAddress)
@@ -38,7 +38,7 @@ KNativePtr Kotlin_WorkerBoundReference_create(KRef value) {
} }
OBJ_GETTER(Kotlin_WorkerBoundReference_deref, KNativePtr holder) { OBJ_GETTER(Kotlin_WorkerBoundReference_deref, KNativePtr holder) {
RETURN_OBJ(reinterpret_cast<KRefSharedHolder*>(holder)->refOrNull()); RETURN_OBJ(reinterpret_cast<KRefSharedHolder*>(holder)->ref<ErrorPolicy::kDefaultValue>());
} }
OBJ_GETTER(Kotlin_WorkerBoundReference_describe, KNativePtr holder) { OBJ_GETTER(Kotlin_WorkerBoundReference_describe, KNativePtr holder) {
+7 -3
View File
@@ -36,12 +36,16 @@ extern "C" id objc_autoreleaseReturnValue(id self);
static void injectToRuntime(); 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 { @implementation KotlinBase {
BackRefFromAssociatedObject refHolder; BackRefFromAssociatedObject refHolder;
} }
-(KRef)toKotlin:(KRef*)OBJ_RESULT { -(KRef)toKotlin:(KRef*)OBJ_RESULT {
RETURN_OBJ(refHolder.ref()); RETURN_OBJ(refHolder.ref<ErrorPolicy::kTerminate>());
} }
+(void)load { +(void)load {
@@ -103,7 +107,7 @@ static void injectToRuntime();
if (refHolder.permanent()) { // TODO: consider storing `isPermanent` to self field. if (refHolder.permanent()) { // TODO: consider storing `isPermanent` to self field.
[super retain]; [super retain];
} else { } else {
refHolder.addRef(); refHolder.addRef<ErrorPolicy::kTerminate>();
} }
return self; return self;
} }
@@ -112,7 +116,7 @@ static void injectToRuntime();
if (refHolder.permanent()) { if (refHolder.permanent()) {
return [super _tryRetain]; return [super _tryRetain];
} else { } else {
return refHolder.tryAddRef(); return refHolder.tryAddRef<ErrorPolicy::kTerminate>();
} }
} }
+38 -35
View File
@@ -81,6 +81,9 @@ static inline KInt objCIndexToKotlinOrThrow(NSUInteger index) {
return 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) @interface NSArray (NSArrayToKotlin)
@end; @end;
@@ -155,7 +158,7 @@ static inline KInt objCIndexToKotlinOrThrow(NSUInteger index) {
} }
- (id)nextObject { - (id)nextObject {
KRef iterator = iteratorHolder.ref(); KRef iterator = iteratorHolder.ref<ErrorPolicy::kTerminate>();
if (Kotlin_Iterator_hasNext(iterator)) { if (Kotlin_Iterator_hasNext(iterator)) {
ObjHolder holder; ObjHolder holder;
return refToObjCOrNSNull(Kotlin_Iterator_next(iterator, holder.slot())); return refToObjCOrNSNull(Kotlin_Iterator_next(iterator, holder.slot()));
@@ -184,17 +187,17 @@ static inline KInt objCIndexToKotlinOrThrow(NSUInteger index) {
} }
-(KRef)toKotlin:(KRef*)OBJ_RESULT { -(KRef)toKotlin:(KRef*)OBJ_RESULT {
RETURN_OBJ(listHolder.ref()); RETURN_OBJ(listHolder.ref<ErrorPolicy::kTerminate>());
} }
-(id)objectAtIndex:(NSUInteger)index { -(id)objectAtIndex:(NSUInteger)index {
ObjHolder kotlinValueHolder; ObjHolder kotlinValueHolder;
KRef kotlinValue = Kotlin_List_get(listHolder.ref(), index, kotlinValueHolder.slot()); KRef kotlinValue = Kotlin_List_get(listHolder.ref<ErrorPolicy::kTerminate>(), index, kotlinValueHolder.slot());
return refToObjCOrNSNull(kotlinValue); return refToObjCOrNSNull(kotlinValue);
} }
-(NSUInteger)count { -(NSUInteger)count {
return Kotlin_Collection_getSize(listHolder.ref()); return Kotlin_Collection_getSize(listHolder.ref<ErrorPolicy::kTerminate>());
} }
@end; @end;
@@ -218,42 +221,42 @@ static inline KInt objCIndexToKotlinOrThrow(NSUInteger index) {
} }
-(KRef)toKotlin:(KRef*)OBJ_RESULT { -(KRef)toKotlin:(KRef*)OBJ_RESULT {
RETURN_OBJ(listHolder.ref()); RETURN_OBJ(listHolder.ref<ErrorPolicy::kTerminate>());
} }
-(id)objectAtIndex:(NSUInteger)index { -(id)objectAtIndex:(NSUInteger)index {
ObjHolder kotlinValueHolder; ObjHolder kotlinValueHolder;
KRef kotlinValue = Kotlin_List_get(listHolder.ref(), index, kotlinValueHolder.slot()); KRef kotlinValue = Kotlin_List_get(listHolder.ref<ErrorPolicy::kTerminate>(), index, kotlinValueHolder.slot());
return refToObjCOrNSNull(kotlinValue); return refToObjCOrNSNull(kotlinValue);
} }
-(NSUInteger)count { -(NSUInteger)count {
return Kotlin_Collection_getSize(listHolder.ref()); return Kotlin_Collection_getSize(listHolder.ref<ErrorPolicy::kTerminate>());
} }
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index { - (void)insertObject:(id)anObject atIndex:(NSUInteger)index {
ObjHolder holder; ObjHolder holder;
KRef kotlinObject = refFromObjCOrNSNull(anObject, holder.slot()); KRef kotlinObject = refFromObjCOrNSNull(anObject, holder.slot());
Kotlin_MutableList_addObjectAtIndex(listHolder.ref(), objCIndexToKotlinOrThrow(index), kotlinObject); Kotlin_MutableList_addObjectAtIndex(listHolder.ref<ErrorPolicy::kTerminate>(), objCIndexToKotlinOrThrow(index), kotlinObject);
} }
- (void)removeObjectAtIndex:(NSUInteger)index { - (void)removeObjectAtIndex:(NSUInteger)index {
Kotlin_MutableList_removeObjectAtIndex(listHolder.ref(), objCIndexToKotlinOrThrow(index)); Kotlin_MutableList_removeObjectAtIndex(listHolder.ref<ErrorPolicy::kTerminate>(), objCIndexToKotlinOrThrow(index));
} }
- (void)addObject:(id)anObject { - (void)addObject:(id)anObject {
ObjHolder holder; ObjHolder holder;
Kotlin_MutableCollection_addObject(listHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); Kotlin_MutableCollection_addObject(listHolder.ref<ErrorPolicy::kTerminate>(), refFromObjCOrNSNull(anObject, holder.slot()));
} }
- (void)removeLastObject { - (void)removeLastObject {
Kotlin_MutableList_removeLastObject(listHolder.ref()); Kotlin_MutableList_removeLastObject(listHolder.ref<ErrorPolicy::kTerminate>());
} }
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
ObjHolder holder; ObjHolder holder;
KRef kotlinObject = refFromObjCOrNSNull(anObject, holder.slot()); KRef kotlinObject = refFromObjCOrNSNull(anObject, holder.slot());
Kotlin_MutableList_setObject(listHolder.ref(), objCIndexToKotlinOrThrow(index), kotlinObject); Kotlin_MutableList_setObject(listHolder.ref<ErrorPolicy::kTerminate>(), objCIndexToKotlinOrThrow(index), kotlinObject);
} }
@end; @end;
@@ -291,26 +294,26 @@ static inline id KSet_getElement(KRef set, id object) {
} }
-(KRef)toKotlin:(KRef*)OBJ_RESULT { -(KRef)toKotlin:(KRef*)OBJ_RESULT {
RETURN_OBJ(setHolder.ref()); RETURN_OBJ(setHolder.ref<ErrorPolicy::kTerminate>());
} }
-(NSUInteger) count { -(NSUInteger) count {
return Kotlin_Collection_getSize(setHolder.ref()); return Kotlin_Collection_getSize(setHolder.ref<ErrorPolicy::kTerminate>());
} }
- (id)member:(id)object { - (id)member:(id)object {
return KSet_getElement(setHolder.ref(), object); return KSet_getElement(setHolder.ref<ErrorPolicy::kTerminate>(), object);
} }
// Not mandatory, just an optimization: // Not mandatory, just an optimization:
- (BOOL)containsObject:(id)anObject { - (BOOL)containsObject:(id)anObject {
ObjHolder holder; ObjHolder holder;
return Kotlin_Set_contains(setHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); return Kotlin_Set_contains(setHolder.ref<ErrorPolicy::kTerminate>(), refFromObjCOrNSNull(anObject, holder.slot()));
} }
- (NSEnumerator*)objectEnumerator { - (NSEnumerator*)objectEnumerator {
ObjHolder holder; ObjHolder holder;
return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref(), holder.slot())]; return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref<ErrorPolicy::kTerminate>(), holder.slot())];
} }
@end; @end;
@@ -375,36 +378,36 @@ static inline id KSet_getElement(KRef set, id object) {
} }
-(KRef)toKotlin:(KRef*)OBJ_RESULT { -(KRef)toKotlin:(KRef*)OBJ_RESULT {
RETURN_OBJ(setHolder.ref()); RETURN_OBJ(setHolder.ref<ErrorPolicy::kTerminate>());
} }
-(NSUInteger) count { -(NSUInteger) count {
return Kotlin_Collection_getSize(setHolder.ref()); return Kotlin_Collection_getSize(setHolder.ref<ErrorPolicy::kTerminate>());
} }
- (id)member:(id)object { - (id)member:(id)object {
return KSet_getElement(setHolder.ref(), object); return KSet_getElement(setHolder.ref<ErrorPolicy::kTerminate>(), object);
} }
// Not mandatory, just an optimization: // Not mandatory, just an optimization:
- (BOOL)containsObject:(id)anObject { - (BOOL)containsObject:(id)anObject {
ObjHolder holder; ObjHolder holder;
return Kotlin_Set_contains(setHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); return Kotlin_Set_contains(setHolder.ref<ErrorPolicy::kTerminate>(), refFromObjCOrNSNull(anObject, holder.slot()));
} }
- (NSEnumerator*)objectEnumerator { - (NSEnumerator*)objectEnumerator {
ObjHolder holder; ObjHolder holder;
return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref(), holder.slot())]; return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref<ErrorPolicy::kTerminate>(), holder.slot())];
} }
- (void)addObject:(id)object { - (void)addObject:(id)object {
ObjHolder holder; ObjHolder holder;
Kotlin_MutableCollection_addObject(setHolder.ref(), refFromObjCOrNSNull(object, holder.slot())); Kotlin_MutableCollection_addObject(setHolder.ref<ErrorPolicy::kTerminate>(), refFromObjCOrNSNull(object, holder.slot()));
} }
- (void)removeObject:(id)object { - (void)removeObject:(id)object {
ObjHolder holder; ObjHolder holder;
Kotlin_MutableCollection_removeObject(setHolder.ref(), refFromObjCOrNSNull(object, holder.slot())); Kotlin_MutableCollection_removeObject(setHolder.ref<ErrorPolicy::kTerminate>(), refFromObjCOrNSNull(object, holder.slot()));
} }
@end; @end;
@@ -441,23 +444,23 @@ static inline id KMap_get(KRef map, id aKey) {
} }
-(KRef)toKotlin:(KRef*)OBJ_RESULT { -(KRef)toKotlin:(KRef*)OBJ_RESULT {
RETURN_OBJ(mapHolder.ref()); RETURN_OBJ(mapHolder.ref<ErrorPolicy::kTerminate>());
} }
// According to documentation, initWithObjects:forKeys:count: is required to be overridden when subclassing. // 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. // But that doesn't make any sense, since this class can't be arbitrary initialized.
-(NSUInteger) count { -(NSUInteger) count {
return Kotlin_Map_getSize(mapHolder.ref()); return Kotlin_Map_getSize(mapHolder.ref<ErrorPolicy::kTerminate>());
} }
- (id)objectForKey:(id)aKey { - (id)objectForKey:(id)aKey {
return KMap_get(mapHolder.ref(), aKey); return KMap_get(mapHolder.ref<ErrorPolicy::kTerminate>(), aKey);
} }
- (NSEnumerator *)keyEnumerator { - (NSEnumerator *)keyEnumerator {
ObjHolder holder; ObjHolder holder;
return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref(), holder.slot())]; return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref<ErrorPolicy::kTerminate>(), holder.slot())];
} }
@end; @end;
@@ -512,20 +515,20 @@ static inline id KMap_get(KRef map, id aKey) {
} }
-(KRef)toKotlin:(KRef*)OBJ_RESULT { -(KRef)toKotlin:(KRef*)OBJ_RESULT {
RETURN_OBJ(mapHolder.ref()); RETURN_OBJ(mapHolder.ref<ErrorPolicy::kTerminate>());
} }
-(NSUInteger) count { -(NSUInteger) count {
return Kotlin_Map_getSize(mapHolder.ref()); return Kotlin_Map_getSize(mapHolder.ref<ErrorPolicy::kTerminate>());
} }
- (id)objectForKey:(id)aKey { - (id)objectForKey:(id)aKey {
return KMap_get(mapHolder.ref(), aKey); return KMap_get(mapHolder.ref<ErrorPolicy::kTerminate>(), aKey);
} }
- (NSEnumerator *)keyEnumerator { - (NSEnumerator *)keyEnumerator {
ObjHolder holder; ObjHolder holder;
return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref(), holder.slot())]; return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref<ErrorPolicy::kTerminate>(), holder.slot())];
} }
- (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey { - (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey {
@@ -537,14 +540,14 @@ static inline id KMap_get(KRef map, id aKey) {
KRef kotlinValue = refFromObjCOrNSNull(anObject, valueHolder.slot()); KRef kotlinValue = refFromObjCOrNSNull(anObject, valueHolder.slot());
Kotlin_MutableMap_set(mapHolder.ref(), kotlinKey, kotlinValue); Kotlin_MutableMap_set(mapHolder.ref<ErrorPolicy::kTerminate>(), kotlinKey, kotlinValue);
} }
- (void)removeObjectForKey:(id)aKey { - (void)removeObjectForKey:(id)aKey {
ObjHolder holder; ObjHolder holder;
KRef kotlinKey = refFromObjCOrNSNull(aKey, holder.slot()); KRef kotlinKey = refFromObjCOrNSNull(aKey, holder.slot());
Kotlin_MutableMap_remove(mapHolder.ref(), kotlinKey); Kotlin_MutableMap_remove(mapHolder.ref<ErrorPolicy::kTerminate>(), kotlinKey);
} }
@end; @end;
@@ -584,4 +587,4 @@ extern "C" id Kotlin_Interop_CreateKotlinMutableDictonaryFromKMap(KRef obj) {
return [[[KotlinMutableDictionary alloc] initWithKMap:obj] autorelease]; return [[[KotlinMutableDictionary alloc] initWithKMap:obj] autorelease];
} }
#endif // KONAN_OBJC_INTEROP #endif // KONAN_OBJC_INTEROP
@@ -30,7 +30,7 @@
} }
-(KRef)ref { -(KRef)ref {
return refHolder.ref(); return refHolder.ref<ErrorPolicy::kTerminate>();
} }
-(void)dealloc { -(void)dealloc {