Do not use Kotlin exceptions from MemorySharedRefs in objc context (#4184)
This commit is contained in:
committed by
GitHub
parent
1ba353291b
commit
3445de9c38
@@ -62,6 +62,7 @@ private fun ObjCObjectBase.superInitCheck(superInitCallResult: ObjCObject?) {
|
||||
|
||||
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")
|
||||
external fun <T> 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 <reified T : Any> unwrapKotlinObjectHolder(holder: Any?): T {
|
||||
return unwrapKotlinObjectHolderImpl(holder!!.objcPtr()) as T
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
// Also see counterpart interop/objc/illegal_sharing.kt
|
||||
@Test fun testSharing() = withWorker {
|
||||
val obj = NSObjectImpl()
|
||||
val array = nsArrayOf(obj)
|
||||
|
||||
assertFalse(obj.isFrozen)
|
||||
|
||||
runInWorker {
|
||||
assertFailsWith<IncorrectDereferenceException> {
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ void Kotlin_Interop_disposeStablePointer(KNativePtr pointer) {
|
||||
|
||||
OBJ_GETTER(Kotlin_Interop_derefStablePointer, KNativePtr pointer) {
|
||||
KRefSharedHolder* holder = reinterpret_cast<KRefSharedHolder*>(pointer);
|
||||
RETURN_OBJ(holder->ref());
|
||||
RETURN_OBJ(holder->ref<ErrorPolicy::kThrow>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 <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
|
||||
|
||||
void KRefSharedHolder::initLocal(ObjHeader* obj) {
|
||||
@@ -47,21 +85,20 @@ void KRefSharedHolder::init(ObjHeader* obj) {
|
||||
obj_ = obj;
|
||||
}
|
||||
|
||||
template <ErrorPolicy errorPolicy>
|
||||
ObjHeader* KRefSharedHolder::ref() const {
|
||||
if (auto* result = refOrNull())
|
||||
return result;
|
||||
|
||||
throwIllegalSharingException(obj_);
|
||||
}
|
||||
|
||||
ObjHeader* KRefSharedHolder::refOrNull() const {
|
||||
if (!isRefAccessible()) {
|
||||
if (!ensureRefAccessible<errorPolicy>(obj_, context_)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AdoptReferenceFromSharedVariable(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 {
|
||||
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 <ErrorPolicy errorPolicy>
|
||||
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<errorPolicy>(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<ErrorPolicy::kThrow>();
|
||||
template void BackRefFromAssociatedObject::addRef<ErrorPolicy::kTerminate>();
|
||||
|
||||
template <ErrorPolicy errorPolicy>
|
||||
bool BackRefFromAssociatedObject::tryAddRef() {
|
||||
static_assert(errorPolicy != ErrorPolicy::kDefaultValue, "Cannot use default return value here");
|
||||
|
||||
// Suboptimal but simple:
|
||||
this->ensureRefAccessible();
|
||||
ObjHeader* obj = this->obj_;
|
||||
ensureRefAccessible<errorPolicy>(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<ErrorPolicy::kIgnore>();
|
||||
ReleaseHeapRef(obj); // Balance TryAddHeapRef.
|
||||
// TODO: consider optimizing for non-shared objects.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool BackRefFromAssociatedObject::tryAddRef<ErrorPolicy::kThrow>();
|
||||
template bool BackRefFromAssociatedObject::tryAddRef<ErrorPolicy::kTerminate>();
|
||||
|
||||
void BackRefFromAssociatedObject::releaseRef() {
|
||||
ForeignRefContext context = context_;
|
||||
if (atomicAdd(&refCount, -1) == 0) {
|
||||
@@ -125,17 +173,19 @@ void BackRefFromAssociatedObject::releaseRef() {
|
||||
}
|
||||
}
|
||||
|
||||
template <ErrorPolicy errorPolicy>
|
||||
ObjHeader* BackRefFromAssociatedObject::ref() const {
|
||||
ensureRefAccessible();
|
||||
if (!ensureRefAccessible<errorPolicy>(obj_, context_)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AdoptReferenceFromSharedVariable(obj_);
|
||||
return obj_;
|
||||
}
|
||||
|
||||
void BackRefFromAssociatedObject::ensureRefAccessible() const {
|
||||
if (!isForeignRefAccessible(obj_, context_)) {
|
||||
throwIllegalSharingException(obj_);
|
||||
}
|
||||
}
|
||||
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kDefaultValue>() const;
|
||||
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kThrow>() const;
|
||||
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kTerminate>() 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<ErrorPolicy::kTerminate>();
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
@@ -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 <ErrorPolicy errorPolicy>
|
||||
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<KRefSharedHolder>::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 <ErrorPolicy errorPolicy>
|
||||
void addRef();
|
||||
|
||||
// Error if called from the wrong worker with non-frozen obj_.
|
||||
template <ErrorPolicy errorPolicy>
|
||||
bool tryAddRef();
|
||||
|
||||
void releaseRef();
|
||||
|
||||
// Error if called from the wrong worker with non-frozen obj_.
|
||||
template <ErrorPolicy errorPolicy>
|
||||
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<BackRefFromAssociatedObject>::value,
|
||||
|
||||
@@ -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<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
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<ErrorPolicy::kTerminate>();
|
||||
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<ErrorPolicy::kThrow>();
|
||||
} catch (ExceptionObjHolder& e) {
|
||||
// TODO: check for IncorrectDereferenceException and possible weak property access
|
||||
// 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) {
|
||||
RETURN_OBJ(reinterpret_cast<KRefSharedHolder*>(holder)->refOrNull());
|
||||
RETURN_OBJ(reinterpret_cast<KRefSharedHolder*>(holder)->ref<ErrorPolicy::kDefaultValue>());
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_WorkerBoundReference_describe, KNativePtr holder) {
|
||||
|
||||
@@ -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<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
+(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<ErrorPolicy::kTerminate>();
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -112,7 +116,7 @@ static void injectToRuntime();
|
||||
if (refHolder.permanent()) {
|
||||
return [super _tryRetain];
|
||||
} else {
|
||||
return refHolder.tryAddRef();
|
||||
return refHolder.tryAddRef<ErrorPolicy::kTerminate>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ErrorPolicy::kTerminate>();
|
||||
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<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
-(id)objectAtIndex:(NSUInteger)index {
|
||||
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);
|
||||
}
|
||||
|
||||
-(NSUInteger)count {
|
||||
return Kotlin_Collection_getSize(listHolder.ref());
|
||||
return Kotlin_Collection_getSize(listHolder.ref<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
@end;
|
||||
@@ -218,42 +221,42 @@ static inline KInt objCIndexToKotlinOrThrow(NSUInteger index) {
|
||||
}
|
||||
|
||||
-(KRef)toKotlin:(KRef*)OBJ_RESULT {
|
||||
RETURN_OBJ(listHolder.ref());
|
||||
RETURN_OBJ(listHolder.ref<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
-(id)objectAtIndex:(NSUInteger)index {
|
||||
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);
|
||||
}
|
||||
|
||||
-(NSUInteger)count {
|
||||
return Kotlin_Collection_getSize(listHolder.ref());
|
||||
return Kotlin_Collection_getSize(listHolder.ref<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
- (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<ErrorPolicy::kTerminate>(), objCIndexToKotlinOrThrow(index), kotlinObject);
|
||||
}
|
||||
|
||||
- (void)removeObjectAtIndex:(NSUInteger)index {
|
||||
Kotlin_MutableList_removeObjectAtIndex(listHolder.ref(), objCIndexToKotlinOrThrow(index));
|
||||
Kotlin_MutableList_removeObjectAtIndex(listHolder.ref<ErrorPolicy::kTerminate>(), objCIndexToKotlinOrThrow(index));
|
||||
}
|
||||
|
||||
- (void)addObject:(id)anObject {
|
||||
ObjHolder holder;
|
||||
Kotlin_MutableCollection_addObject(listHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot()));
|
||||
Kotlin_MutableCollection_addObject(listHolder.ref<ErrorPolicy::kTerminate>(), refFromObjCOrNSNull(anObject, holder.slot()));
|
||||
}
|
||||
|
||||
- (void)removeLastObject {
|
||||
Kotlin_MutableList_removeLastObject(listHolder.ref());
|
||||
Kotlin_MutableList_removeLastObject(listHolder.ref<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
- (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<ErrorPolicy::kTerminate>(), 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<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
-(NSUInteger) count {
|
||||
return Kotlin_Collection_getSize(setHolder.ref());
|
||||
return Kotlin_Collection_getSize(setHolder.ref<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
- (id)member:(id)object {
|
||||
return KSet_getElement(setHolder.ref(), object);
|
||||
return KSet_getElement(setHolder.ref<ErrorPolicy::kTerminate>(), 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<ErrorPolicy::kTerminate>(), 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<ErrorPolicy::kTerminate>(), 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<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
-(NSUInteger) count {
|
||||
return Kotlin_Collection_getSize(setHolder.ref());
|
||||
return Kotlin_Collection_getSize(setHolder.ref<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
- (id)member:(id)object {
|
||||
return KSet_getElement(setHolder.ref(), object);
|
||||
return KSet_getElement(setHolder.ref<ErrorPolicy::kTerminate>(), 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<ErrorPolicy::kTerminate>(), 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<ErrorPolicy::kTerminate>(), holder.slot())];
|
||||
}
|
||||
|
||||
- (void)addObject:(id)object {
|
||||
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 {
|
||||
ObjHolder holder;
|
||||
Kotlin_MutableCollection_removeObject(setHolder.ref(), refFromObjCOrNSNull(object, holder.slot()));
|
||||
Kotlin_MutableCollection_removeObject(setHolder.ref<ErrorPolicy::kTerminate>(), 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<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
// 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<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
- (id)objectForKey:(id)aKey {
|
||||
return KMap_get(mapHolder.ref(), aKey);
|
||||
return KMap_get(mapHolder.ref<ErrorPolicy::kTerminate>(), aKey);
|
||||
}
|
||||
|
||||
- (NSEnumerator *)keyEnumerator {
|
||||
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;
|
||||
@@ -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<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
-(NSUInteger) count {
|
||||
return Kotlin_Map_getSize(mapHolder.ref());
|
||||
return Kotlin_Map_getSize(mapHolder.ref<ErrorPolicy::kTerminate>());
|
||||
}
|
||||
|
||||
- (id)objectForKey:(id)aKey {
|
||||
return KMap_get(mapHolder.ref(), aKey);
|
||||
return KMap_get(mapHolder.ref<ErrorPolicy::kTerminate>(), aKey);
|
||||
}
|
||||
|
||||
- (NSEnumerator *)keyEnumerator {
|
||||
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 {
|
||||
@@ -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<ErrorPolicy::kTerminate>(), 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<ErrorPolicy::kTerminate>(), kotlinKey);
|
||||
}
|
||||
|
||||
@end;
|
||||
@@ -584,4 +587,4 @@ extern "C" id Kotlin_Interop_CreateKotlinMutableDictonaryFromKMap(KRef obj) {
|
||||
return [[[KotlinMutableDictionary alloc] initWithKMap:obj] autorelease];
|
||||
}
|
||||
|
||||
#endif // KONAN_OBJC_INTEROP
|
||||
#endif // KONAN_OBJC_INTEROP
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
}
|
||||
|
||||
-(KRef)ref {
|
||||
return refHolder.ref();
|
||||
return refHolder.ref<ErrorPolicy::kTerminate>();
|
||||
}
|
||||
|
||||
-(void)dealloc {
|
||||
|
||||
Reference in New Issue
Block a user