diff --git a/runtime/src/main/cpp/Exceptions.h b/runtime/src/main/cpp/Exceptions.h index b0472311ea1..71509982139 100644 --- a/runtime/src/main/cpp/Exceptions.h +++ b/runtime/src/main/cpp/Exceptions.h @@ -53,6 +53,7 @@ void RUNTIME_NORETURN ThrowIllegalCharacterConversionException(); void RUNTIME_NORETURN ThrowIllegalArgumentException(); void RUNTIME_NORETURN ThrowInvalidMutabilityException(KConstRef where); void RUNTIME_NORETURN ThrowIncorrectDereferenceException(); +void RUNTIME_NORETURN ThrowIllegalObjectSharingException(KConstNativePtr typeInfo, KConstNativePtr address); // Prints out mesage of Throwable. void PrintThrowable(KRef); diff --git a/runtime/src/main/cpp/Memory.cpp b/runtime/src/main/cpp/Memory.cpp index 7a832793466..6e3a6e1748f 100644 --- a/runtime/src/main/cpp/Memory.cpp +++ b/runtime/src/main/cpp/Memory.cpp @@ -351,6 +351,11 @@ namespace { // TODO: can we pass this variable as an explicit argument? THREAD_LOCAL_VARIABLE MemoryState* memoryState = nullptr; +// TODO: use widely. +inline void EnsureRuntimeInitialized() { + RuntimeCheck(memoryState != nullptr, "Unable to execute Kotlin code on uninitialized thread"); +} + constexpr int kFrameOverlaySlots = sizeof(FrameOverlay) / sizeof(ObjHeader**); inline bool isFreeable(const ContainerHeader* header) { @@ -407,6 +412,21 @@ inline void unlock(KInt* spinlock) { } // namespace +void KRefSharedHolder::initRefOwner() { + RuntimeAssert(owner_ == nullptr, "Must be uninitialized"); + owner_ = memoryState; +} + +void KRefSharedHolder::verifyRefOwner() const { + // Note: checking for 'permanentOrFrozen()' and retrieving 'type_info()' + // are supposed to be correct even for unowned object. + if (owner_ != memoryState && !obj_->container()->permanentOrFrozen()) { + EnsureRuntimeInitialized(); + // TODO: add some info about the owner. + ThrowIllegalObjectSharingException(obj_->type_info(), obj_); + } +} + extern "C" { // Ensure LLVM never throws theStaticObjectsContainer away. diff --git a/runtime/src/main/cpp/Memory.h b/runtime/src/main/cpp/Memory.h index a0e956d54ea..d530d4b4490 100644 --- a/runtime/src/main/cpp/Memory.h +++ b/runtime/src/main/cpp/Memory.h @@ -501,4 +501,35 @@ class ObjHolder { ObjHeader* obj_; }; +class KRefSharedHolder { + public: + inline ObjHeader** slotToInit() { + initRefOwner(); + return &obj_; + } + + inline void init(ObjHeader* obj) { + SetRef(slotToInit(), obj); + } + + inline ObjHeader* ref() const { + verifyRefOwner(); + return obj_; + } + + inline void dispose() { + verifyRefOwner(); + UpdateRef(&obj_, nullptr); + } + + private: + typedef MemoryState* RefOwner; + + ObjHeader* obj_; + RefOwner owner_; + + void initRefOwner(); + void verifyRefOwner() const; +}; + #endif // RUNTIME_MEMORY_H diff --git a/runtime/src/main/cpp/ObjCExport.mm b/runtime/src/main/cpp/ObjCExport.mm index 7da7ae468cb..45f7821b9e6 100644 --- a/runtime/src/main/cpp/ObjCExport.mm +++ b/runtime/src/main/cpp/ObjCExport.mm @@ -136,11 +136,11 @@ static inline id AtomicSetAssociatedObject(ObjHeader* obj, id associatedObject) @end; @implementation KotlinBase { - KRef kotlinObj; + KRefSharedHolder refHolder; } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(kotlinObj); + RETURN_OBJ(refHolder.ref()); } +(void)initialize { @@ -165,7 +165,7 @@ static inline id AtomicSetAssociatedObject(ObjHeader* obj, id associatedObject) class_getName(object_getClass(self))]; } - AllocInstanceWithAssociatedObject(typeInfo, result, &result->kotlinObj); + AllocInstanceWithAssociatedObject(typeInfo, result, result->refHolder.slotToInit()); return result; } @@ -173,7 +173,7 @@ static inline id AtomicSetAssociatedObject(ObjHeader* obj, id associatedObject) +(instancetype)createWrapper:(ObjHeader*)obj { KotlinBase* result = [super allocWithZone:nil]; // TODO: should we call NSObject.init ? - UpdateRef(&result->kotlinObj, obj); + result->refHolder.init(obj); [result autorelease]; if (!obj->permanent()) { @@ -185,7 +185,7 @@ static inline id AtomicSetAssociatedObject(ObjHeader* obj, id associatedObject) } -(instancetype)retain { - ObjHeader* obj = kotlinObj; + ObjHeader* obj = refHolder.ref(); if (obj->permanent()) { // TODO: consider storing `isPermanent` to self field. [super retain]; } else { @@ -195,7 +195,7 @@ static inline id AtomicSetAssociatedObject(ObjHeader* obj, id associatedObject) } -(BOOL)_tryRetain { - ObjHeader* obj = kotlinObj; + ObjHeader* obj = refHolder.ref(); if (obj->permanent()) { return [super _tryRetain]; } else if (!obj->has_meta_object()) { @@ -209,16 +209,16 @@ static inline id AtomicSetAssociatedObject(ObjHeader* obj, id associatedObject) } -(oneway void)release { - ObjHeader* obj = kotlinObj; + ObjHeader* obj = refHolder.ref(); if (obj->permanent()) { [super release]; } else { - ReleaseRefFromAssociatedObject(kotlinObj); + ReleaseRefFromAssociatedObject(obj); } } -(void)releaseAsAssociatedObject { - RuntimeAssert(!kotlinObj->permanent(), ""); + RuntimeAssert(!refHolder.ref()->permanent(), ""); [super release]; } diff --git a/runtime/src/main/cpp/ObjCExportCollections.mm b/runtime/src/main/cpp/ObjCExportCollections.mm index a1a6024bbef..cd265dfa0bd 100644 --- a/runtime/src/main/cpp/ObjCExportCollections.mm +++ b/runtime/src/main/cpp/ObjCExportCollections.mm @@ -182,21 +182,22 @@ static inline OBJ_GETTER(invokeAndAssociate, KRef (*func)(KRef* result), id obj) @end; @implementation KIteratorAsNSEnumerator { - KRef iterator; + KRefSharedHolder iteratorHolder; } -(void)dealloc { - UpdateRef(&iterator, nullptr); + iteratorHolder.dispose(); [super dealloc]; } +(id)createWithKIterator:(KRef)iterator { KIteratorAsNSEnumerator* result = [[[KIteratorAsNSEnumerator alloc] init] autorelease]; - UpdateRef(&result->iterator, iterator); + result->iteratorHolder.init(iterator); return result; } - (id)nextObject { + KRef iterator = iteratorHolder.ref(); if (Kotlin_Iterator_hasNext(iterator)) { ObjHolder holder; return refToObjCOrNSNull(Kotlin_Iterator_next(iterator, holder.slot())); @@ -210,32 +211,32 @@ static inline OBJ_GETTER(invokeAndAssociate, KRef (*func)(KRef* result), id obj) @end; @implementation KListAsNSArray { - KRef list; + KRefSharedHolder listHolder; } -(void)dealloc { - UpdateRef(&list, nullptr); + listHolder.dispose(); [super dealloc]; } +(id)createWithKList:(KRef)list { KListAsNSArray* result = [[[KListAsNSArray alloc] init] autorelease]; - UpdateRef(&result->list, list); + result->listHolder.init(list); return result; } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(list); + RETURN_OBJ(listHolder.ref()); } -(id)objectAtIndex:(NSUInteger)index { ObjHolder kotlinValueHolder; - KRef kotlinValue = Kotlin_List_get(list, index, kotlinValueHolder.slot()); + KRef kotlinValue = Kotlin_List_get(listHolder.ref(), index, kotlinValueHolder.slot()); return refToObjCOrNSNull(kotlinValue); } -(NSUInteger)count { - return Kotlin_Collection_getSize(list); + return Kotlin_Collection_getSize(listHolder.ref()); } @end; @@ -244,57 +245,57 @@ static inline OBJ_GETTER(invokeAndAssociate, KRef (*func)(KRef* result), id obj) @end; @implementation KMutableListAsNSMutableArray { - KRef list; + KRefSharedHolder listHolder; } -(void)dealloc { - UpdateRef(&list, nullptr); + listHolder.dispose(); [super dealloc]; } +(id)createWithKList:(KRef)list { KMutableListAsNSMutableArray* result = [[[KMutableListAsNSMutableArray alloc] init] autorelease]; - UpdateRef(&result->list, list); + result->listHolder.init(list); return result; } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(list); + RETURN_OBJ(listHolder.ref()); } -(id)objectAtIndex:(NSUInteger)index { ObjHolder kotlinValueHolder; - KRef kotlinValue = Kotlin_List_get(list, index, kotlinValueHolder.slot()); + KRef kotlinValue = Kotlin_List_get(listHolder.ref(), index, kotlinValueHolder.slot()); return refToObjCOrNSNull(kotlinValue); } -(NSUInteger)count { - return Kotlin_Collection_getSize(list); + return Kotlin_Collection_getSize(listHolder.ref()); } - (void)insertObject:(id)anObject atIndex:(NSUInteger)index { ObjHolder holder; KRef kotlinObject = refFromObjCOrNSNull(anObject, holder.slot()); - Kotlin_MutableList_addObjectAtIndex(list, objCIndexToKotlinOrThrow(index), kotlinObject); + Kotlin_MutableList_addObjectAtIndex(listHolder.ref(), objCIndexToKotlinOrThrow(index), kotlinObject); } - (void)removeObjectAtIndex:(NSUInteger)index { - Kotlin_MutableList_removeObjectAtIndex(list, objCIndexToKotlinOrThrow(index)); + Kotlin_MutableList_removeObjectAtIndex(listHolder.ref(), objCIndexToKotlinOrThrow(index)); } - (void)addObject:(id)anObject { ObjHolder holder; - Kotlin_MutableCollection_addObject(list, refFromObjCOrNSNull(anObject, holder.slot())); + Kotlin_MutableCollection_addObject(listHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); } - (void)removeLastObject { - Kotlin_MutableList_removeLastObject(list); + Kotlin_MutableList_removeLastObject(listHolder.ref()); } - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { ObjHolder holder; KRef kotlinObject = refFromObjCOrNSNull(anObject, holder.slot()); - Kotlin_MutableList_setObject(list, objCIndexToKotlinOrThrow(index), kotlinObject); + Kotlin_MutableList_setObject(listHolder.ref(), objCIndexToKotlinOrThrow(index), kotlinObject); } @end; @@ -317,41 +318,41 @@ static inline id KSet_getElement(KRef set, id object) { } @implementation KSetAsNSSet { - KRef set; + KRefSharedHolder setHolder; } -(void)dealloc { - UpdateRef(&set, nullptr); + setHolder.dispose(); [super dealloc]; } +(id)createWithKSet:(KRef)set { KSetAsNSSet* result = [[[KSetAsNSSet alloc] init] autorelease]; - UpdateRef(&result->set, set); + result->setHolder.init(set); return result; } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(set); + RETURN_OBJ(setHolder.ref()); } -(NSUInteger) count { - return Kotlin_Collection_getSize(set); + return Kotlin_Collection_getSize(setHolder.ref()); } - (id)member:(id)object { - return KSet_getElement(set, object); + return KSet_getElement(setHolder.ref(), object); } // Not mandatory, just an optimization: - (BOOL)containsObject:(id)anObject { ObjHolder holder; - return Kotlin_Set_contains(set, refFromObjCOrNSNull(anObject, holder.slot())); + return Kotlin_Set_contains(setHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); } - (NSEnumerator*)objectEnumerator { ObjHolder holder; - return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(set, holder.slot())]; + return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref(), holder.slot())]; } @end; @@ -359,13 +360,13 @@ static inline id KSet_getElement(KRef set, id object) { @end; @implementation KotlinMutableSet { - KRef set; + KRefSharedHolder setHolder; } -(instancetype)init { if (self = [super init]) { Kotlin_initRuntimeIfNeeded(); - Kotlin_MutableSet_createWithCapacity(8, &self->set); + Kotlin_MutableSet_createWithCapacity(8, self->setHolder.slotToInit()); } return self; @@ -374,7 +375,7 @@ static inline id KSet_getElement(KRef set, id object) { - (instancetype)initWithCapacity:(NSUInteger)numItems { if (self = [super init]) { Kotlin_initRuntimeIfNeeded(); - Kotlin_MutableSet_createWithCapacity(objCCapacityToKotlin(numItems), &self->set); + Kotlin_MutableSet_createWithCapacity(objCCapacityToKotlin(numItems), self->setHolder.slotToInit()); } return self; @@ -395,47 +396,49 @@ static inline id KSet_getElement(KRef set, id object) { // ? -(void)dealloc { - UpdateRef(&set, nullptr); + setHolder.dispose(); [super dealloc]; } -+(id)createWithKSet:(KRef)set { - KotlinMutableSet* result = [[[super allocWithZone:nullptr] init] autorelease]; - UpdateRef(&result->set, set); - return result; +-(instancetype)initWithKSet:(KRef)set { + if (self = [super init]) { + setHolder.init(set); + } + + return self; } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(set); + RETURN_OBJ(setHolder.ref()); } -(NSUInteger) count { - return Kotlin_Collection_getSize(set); + return Kotlin_Collection_getSize(setHolder.ref()); } - (id)member:(id)object { - return KSet_getElement(set, object); + return KSet_getElement(setHolder.ref(), object); } // Not mandatory, just an optimization: - (BOOL)containsObject:(id)anObject { ObjHolder holder; - return Kotlin_Set_contains(set, refFromObjCOrNSNull(anObject, holder.slot())); + return Kotlin_Set_contains(setHolder.ref(), refFromObjCOrNSNull(anObject, holder.slot())); } - (NSEnumerator*)objectEnumerator { ObjHolder holder; - return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(set, holder.slot())]; + return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Set_iterator(setHolder.ref(), holder.slot())]; } - (void)addObject:(id)object { ObjHolder holder; - Kotlin_MutableCollection_addObject(set, refFromObjCOrNSNull(object, holder.slot())); + Kotlin_MutableCollection_addObject(setHolder.ref(), refFromObjCOrNSNull(object, holder.slot())); } - (void)removeObject:(id)object { ObjHolder holder; - Kotlin_MutableCollection_removeObject(set, refFromObjCOrNSNull(object, holder.slot())); + Kotlin_MutableCollection_removeObject(setHolder.ref(), refFromObjCOrNSNull(object, holder.slot())); } @end; @@ -457,38 +460,38 @@ static inline id KMap_get(KRef map, id aKey) { } @implementation KMapAsNSDictionary { - KRef map; + KRefSharedHolder mapHolder; } -(void)dealloc { - UpdateRef(&map, nullptr); + mapHolder.dispose(); [super dealloc]; } +(id)createWithKMap:(KRef)map { KMapAsNSDictionary* result = [[[KMapAsNSDictionary alloc] init] autorelease]; - UpdateRef(&result->map, map); + result->mapHolder.init(map); return result; } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(map); + 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(map); + return Kotlin_Map_getSize(mapHolder.ref()); } - (id)objectForKey:(id)aKey { - return KMap_get(map, aKey); + return KMap_get(mapHolder.ref(), aKey); } - (NSEnumerator *)keyEnumerator { ObjHolder holder; - return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(map, holder.slot())]; + return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref(), holder.slot())]; } @end; @@ -497,18 +500,18 @@ static inline id KMap_get(KRef map, id aKey) { @end; @implementation KotlinMutableDictionary { - KRef map; + KRefSharedHolder mapHolder; } -(void)dealloc { - UpdateRef(&map, nullptr); + mapHolder.dispose(); [super dealloc]; } -(instancetype)init { if (self = [super init]) { Kotlin_initRuntimeIfNeeded(); - Kotlin_MutableMap_createWithCapacity(8, &self->map); + Kotlin_MutableMap_createWithCapacity(8, self->mapHolder.slotToInit()); } return self; } @@ -522,32 +525,34 @@ static inline id KMap_get(KRef map, id aKey) { - (instancetype)initWithCapacity:(NSUInteger)numItems { if (self = [super init]) { Kotlin_initRuntimeIfNeeded(); - Kotlin_MutableMap_createWithCapacity(objCCapacityToKotlin(numItems), &self->map); + Kotlin_MutableMap_createWithCapacity(objCCapacityToKotlin(numItems), self->mapHolder.slotToInit()); } return self; } -+(id)createWithKMap:(KRef)map { - KotlinMutableDictionary* result = [[[KotlinMutableDictionary alloc] init] autorelease]; - UpdateRef(&result->map, map); - return result; +-(instancetype)initWithKMap:(KRef)map { + if (self = [super init]) { + mapHolder.init(map); + } + + return self; } -(KRef)toKotlin:(KRef*)OBJ_RESULT { - RETURN_OBJ(map); + RETURN_OBJ(mapHolder.ref()); } -(NSUInteger) count { - return Kotlin_Map_getSize(map); + return Kotlin_Map_getSize(mapHolder.ref()); } - (id)objectForKey:(id)aKey { - return KMap_get(map, aKey); + return KMap_get(mapHolder.ref(), aKey); } - (NSEnumerator *)keyEnumerator { ObjHolder holder; - return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(map, holder.slot())]; + return [KIteratorAsNSEnumerator createWithKIterator:Kotlin_Map_keyIterator(mapHolder.ref(), holder.slot())]; } - (void)setObject:(id)anObject forKey:(id)aKey { @@ -559,14 +564,14 @@ static inline id KMap_get(KRef map, id aKey) { KRef kotlinValue = refFromObjCOrNSNull(anObject, valueHolder.slot()); - Kotlin_MutableMap_set(map, kotlinKey, kotlinValue); + Kotlin_MutableMap_set(mapHolder.ref(), kotlinKey, kotlinValue); } - (void)removeObjectForKey:(id)aKey { ObjHolder holder; KRef kotlinKey = refFromObjCOrNSNull(aKey, holder.slot()); - Kotlin_MutableMap_remove(map, kotlinKey); + Kotlin_MutableMap_remove(mapHolder.ref(), kotlinKey); } @end; @@ -595,7 +600,7 @@ extern "C" id Kotlin_Interop_CreateNSSetFromKSet(KRef obj) { } extern "C" id Kotlin_Interop_CreateKotlinMutableSetFromKSet(KRef obj) { - return [KotlinMutableSet createWithKSet:obj]; + return [[[KotlinMutableSet alloc] initWithKSet:obj] autorelease]; } extern "C" id Kotlin_Interop_CreateNSDictionaryFromKMap(KRef obj) { @@ -603,7 +608,7 @@ extern "C" id Kotlin_Interop_CreateNSDictionaryFromKMap(KRef obj) { } extern "C" id Kotlin_Interop_CreateKotlinMutableDictonaryFromKMap(KRef obj) { - return [KotlinMutableDictionary createWithKMap:obj]; + return [[[KotlinMutableDictionary alloc] initWithKMap:obj] autorelease]; } // Imported to ObjCExportUtils.kt: diff --git a/runtime/src/main/cpp/ObjCInteropUtils.mm b/runtime/src/main/cpp/ObjCInteropUtils.mm index ee60e78643a..96860e87c29 100644 --- a/runtime/src/main/cpp/ObjCInteropUtils.mm +++ b/runtime/src/main/cpp/ObjCInteropUtils.mm @@ -21,6 +21,7 @@ #import #import #import +#import "Memory.h" namespace { Class nsStringClass = nullptr; @@ -103,22 +104,22 @@ id MissingInitImp(id self, SEL _cmd) { @end; @implementation KotlinObjectHolder { - KRef ref_; + KRefSharedHolder refHolder; }; -(id)initWithRef:(KRef)ref { if (self = [super init]) { - UpdateRef(&ref_, ref); + refHolder.init(ref); } return self; } -(KRef)ref { - return ref_; + return refHolder.ref(); } -(void)dealloc { - UpdateRef(&ref_, nullptr); + refHolder.dispose(); [super dealloc]; } diff --git a/runtime/src/main/cpp/Types.h b/runtime/src/main/cpp/Types.h index f26dddf13f5..1989ad8f216 100644 --- a/runtime/src/main/cpp/Types.h +++ b/runtime/src/main/cpp/Types.h @@ -50,6 +50,8 @@ typedef float KFloat; typedef double KDouble; typedef void* KNativePtr; +typedef const void* KConstNativePtr; + typedef ObjHeader* KRef; typedef const ObjHeader* KConstRef; typedef const ArrayHeader* KString; diff --git a/runtime/src/main/kotlin/kotlin/Any.kt b/runtime/src/main/kotlin/kotlin/Any.kt index 7e8a7499815..e060aa8ef70 100644 --- a/runtime/src/main/kotlin/kotlin/Any.kt +++ b/runtime/src/main/kotlin/kotlin/Any.kt @@ -33,8 +33,7 @@ public open class Any { * * Whenever it is invoked on the same object more than once, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. * * If two objects are equal according to the equals() method, then calling the hashCode method on each of the two objects must produce the same integer result. */ - @SymbolName("Kotlin_Any_hashCode") - external public open fun hashCode(): Int + public open fun hashCode(): Int = this.identityHashCode() /** * Returns a string representation of the object. @@ -42,10 +41,15 @@ public open class Any { public open fun toString(): String { val kClass = this::class val className = kClass.qualifiedName ?: kClass.simpleName ?: "" + // TODO: consider using [identityHashCode]. val unsignedHashCode = this.hashCode().toLong() and 0xffffffffL val hashCodeStr = unsignedHashCode.toString(16) return "$className@$hashCodeStr" } } +@PublishedApi +@SymbolName("Kotlin_Any_hashCode") +external internal fun Any.identityHashCode(): Int + public fun Any?.hashCode() = if (this != null) this.hashCode() else 0 \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/native/concurrent/Freezing.kt b/runtime/src/main/kotlin/kotlin/native/concurrent/Freezing.kt index 7fce120c689..4b3f326358f 100644 --- a/runtime/src/main/kotlin/kotlin/native/concurrent/Freezing.kt +++ b/runtime/src/main/kotlin/kotlin/native/concurrent/Freezing.kt @@ -19,8 +19,7 @@ public class FreezingException(toFreeze: Any, blocker: Any) : * * @param where a frozen object that was attempted to mutate */ -public class InvalidMutabilityException(where: Any) : - RuntimeException("mutation attempt of frozen $where (hash is 0x${where.hashCode().toString(16)})") +public class InvalidMutabilityException(message: String) : RuntimeException(message) /** * Freezes object subgraph reachable from this object. Frozen objects can be freely diff --git a/runtime/src/main/kotlin/kotlin/native/concurrent/Internal.kt b/runtime/src/main/kotlin/kotlin/native/concurrent/Internal.kt index bf682ec4e5d..0b757b7b651 100644 --- a/runtime/src/main/kotlin/kotlin/native/concurrent/Internal.kt +++ b/runtime/src/main/kotlin/kotlin/native/concurrent/Internal.kt @@ -6,6 +6,7 @@ package kotlin.native.concurrent import kotlin.native.internal.ExportForCppRuntime +import kotlin.reflect.KClass import kotlinx.cinterop.* // Implementation details. @@ -69,11 +70,22 @@ internal fun ThrowFreezingException(toFreeze: Any, blocker: Any): Nothing = @ExportForCppRuntime internal fun ThrowInvalidMutabilityException(where: Any): Nothing { - val kClass = where::class + val description = debugDescription(where::class, where.identityHashCode()) + throw InvalidMutabilityException("mutation attempt of frozen $description") +} + +@ExportForCppRuntime +internal fun ThrowIllegalObjectSharingException(typeInfo: NativePtr, address: NativePtr) { + val kClass = kotlin.native.internal.KClassImpl(typeInfo) + val description = debugDescription(kClass, address.toLong().toInt()) + throw IncorrectDereferenceException("illegal attempt to access non-shared $description from other thread") +} + +private fun debugDescription(kClass: KClass<*>, identity: Int): String { val className = kClass.qualifiedName ?: kClass.simpleName ?: "" - val unsignedHashCode = where.hashCode().toLong() and 0xffffffffL - val hashCodeStr = unsignedHashCode.toString(16) - throw InvalidMutabilityException("$className@$hashCodeStr") + val unsignedIdentity = identity.toLong() and 0xffffffffL + val identityStr = unsignedIdentity.toString(16) + return "$className@$identityStr" } @SymbolName("Kotlin_AtomicReference_checkIfFrozen")