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)
// 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
}
+10
View File
@@ -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.
}
}
+1 -1
View File
@@ -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>());
}
}
+74 -24
View File
@@ -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"
+16 -5
View File
@@ -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,
+3 -3
View File
@@ -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) {
+7 -3
View File
@@ -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>();
}
}
+38 -35
View File
@@ -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 {