[K/N] Handle permanent objects in new MM MemorySharedRefs ^KT-56233

Do not create a foreign ref to the permanent objects. There's no need to
do it, and, moreover, this ref would have leaked.
This commit is contained in:
Alexander Shabalin
2023-03-31 16:55:29 +02:00
committed by Space Team
parent 1f1b26f2a5
commit 8a8aeed998
4 changed files with 35 additions and 4 deletions
@@ -104,6 +104,10 @@ void KRefSharedHolder::dispose() {
DeinitForeignRef(obj_, context_); DeinitForeignRef(obj_, context_);
} }
void BackRefFromAssociatedObject::initForPermanentObject(ObjHeader* obj) {
initAndAddRef(obj);
}
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;
@@ -198,3 +202,7 @@ ObjHeader* BackRefFromAssociatedObject::ref() const {
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kDefaultValue>() const; template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kDefaultValue>() const;
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kThrow>() const; template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kThrow>() const;
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kTerminate>() const; template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kTerminate>() const;
ObjHeader* BackRefFromAssociatedObject::refPermanent() const {
return ref<ErrorPolicy::kIgnore>();
}
@@ -46,6 +46,7 @@ static_assert(std::is_trivially_destructible_v<KRefSharedHolder>, "KRefSharedHol
class BackRefFromAssociatedObject { class BackRefFromAssociatedObject {
public: public:
void initForPermanentObject(ObjHeader* obj);
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_. // Error if refCount is zero and it's called from the wrong worker with non-frozen obj_.
@@ -65,6 +66,8 @@ class BackRefFromAssociatedObject {
template <ErrorPolicy errorPolicy> template <ErrorPolicy errorPolicy>
ObjHeader* ref() const; ObjHeader* ref() const;
ObjHeader* refPermanent() const;
private: private:
ObjHeader* obj_; // May be null before [initAndAddRef] or after [detach]. ObjHeader* obj_; // May be null before [initAndAddRef] or after [detach].
ForeignRefContext context_; ForeignRefContext context_;
@@ -41,8 +41,15 @@ void KRefSharedHolder::dispose() {
DeinitForeignRef(obj_, context_); DeinitForeignRef(obj_, context_);
} }
void BackRefFromAssociatedObject::initForPermanentObject(ObjHeader* obj) {
RuntimeAssert(obj != nullptr, "must not be null");
RuntimeAssert(obj->permanent(), "Can only be called with permanent object");
obj_ = obj;
}
void BackRefFromAssociatedObject::initAndAddRef(ObjHeader* obj) { void BackRefFromAssociatedObject::initAndAddRef(ObjHeader* obj) {
RuntimeAssert(obj != nullptr, "must not be null"); RuntimeAssert(obj != nullptr, "must not be null");
RuntimeAssert(!obj->permanent(), "Can only be called with non-permanent object");
obj_ = obj; obj_ = obj;
// Generally a specialized addRef below: // Generally a specialized addRef below:
@@ -126,3 +133,7 @@ ObjHeader* BackRefFromAssociatedObject::ref() const {
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kDefaultValue>() const; template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kDefaultValue>() const;
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kThrow>() const; template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kThrow>() const;
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kTerminate>() const; template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kTerminate>() const;
ObjHeader* BackRefFromAssociatedObject::refPermanent() const {
return obj_;
}
@@ -42,7 +42,11 @@ static void injectToRuntime();
} }
-(KRef)toKotlin:(KRef*)OBJ_RESULT { -(KRef)toKotlin:(KRef*)OBJ_RESULT {
RETURN_OBJ(refHolder.ref<ErrorPolicy::kTerminate>()); if (permanent) {
RETURN_OBJ(refHolder.refPermanent());
} else {
RETURN_OBJ(refHolder.ref<ErrorPolicy::kTerminate>());
}
} }
+(void)load { +(void)load {
@@ -88,10 +92,11 @@ static void injectToRuntime();
KotlinBase* candidate = [super allocWithZone:nil]; KotlinBase* candidate = [super allocWithZone:nil];
// TODO: should we call NSObject.init ? // TODO: should we call NSObject.init ?
candidate->refHolder.initAndAddRef(obj); bool permanent = obj->permanent();
candidate->permanent = obj->permanent(); candidate->permanent = permanent;
if (!obj->permanent()) { // TODO: permanent objects should probably be supported as custom types. if (!permanent) { // TODO: permanent objects should probably be supported as custom types.
candidate->refHolder.initAndAddRef(obj);
if (!isShareable(obj)) { if (!isShareable(obj)) {
SetAssociatedObject(obj, candidate); SetAssociatedObject(obj, candidate);
} else { } else {
@@ -105,6 +110,8 @@ static void injectToRuntime();
return objc_retain(old); return objc_retain(old);
} }
} }
} else {
candidate->refHolder.initForPermanentObject(obj);
} }
return candidate; return candidate;
@@ -136,6 +143,8 @@ static void injectToRuntime();
} }
-(void)releaseAsAssociatedObject:(ReleaseMode)mode { -(void)releaseAsAssociatedObject:(ReleaseMode)mode {
RuntimeAssert(!permanent, "Cannot be called on permanent objects");
// This function is called by the GC. It made a decision to reclaim Kotlin object, and runs // This function is called by the GC. It made a decision to reclaim Kotlin object, and runs
// deallocation hooks at the moment, including deallocation of the "associated object" ([self]) // deallocation hooks at the moment, including deallocation of the "associated object" ([self])
// using the [super release] call below. // using the [super release] call below.