objc_object::rootRetain(bool tryRetain, objc_object::RRVariant variant)
{
// 不处理 TaggedPointer 直接 return
if (slowpath(isTaggedPointer())) return (id)this;
...
do {
transcribeToSideTable = false;
newisa = oldisa;
if (slowpath(!newisa.nonpointer)) {
// 非 nonpointer 通过 sidetable 处理
ClearExclusive(&isa.bits);
if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
else return sidetable_retain(sideTableLocked);
}
...
uintptr_t carry; // 标志 extra_rc 容量是否还能够承受
newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry); // extra_rc++
if (slowpath(carry)) {
// 超出 extra_rc 容量
// newisa.extra_rc++ overflowed
if (variant != RRVariant::Full) {
ClearExclusive(&isa.bits);
return rootRetain_overflow(tryRetain);
}
// 保留一般的引用计数,并将另一半拷贝到 side table
// Leave half of the retain counts inline and
// prepare to copy the other half to the side table.
if (!tryRetain && !sideTableLocked) sidetable_lock();
sideTableLocked = true;
transcribeToSideTable = true;
newisa.extra_rc = RC_HALF;
newisa.has_sidetable_rc = true;
}
} while (slowpath(!StoreExclusive(&isa.bits, &oldisa.bits, newisa.bits)));
if (variant == RRVariant::Full) {
if (slowpath(transcribeToSideTable)) {
// Copy the other half of the retain counts to the side table.
sidetable_addExtraRC_nolock(RC_HALF);
}
if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
} else {
ASSERT(!transcribeToSideTable);
ASSERT(!sideTableLocked);
}
return (id)this;
}
小结
TaggedPointer 不处理,直接 return
Nonpointer isa
BITFIELD 和 SideTable 结合使用
当 BITFIELD 的 extra_rc 容量足够的时候持续 ++
当 BITFIELD 的 extra_rc 容量不够的时候
extra_rc 减半,拷贝一半到 SideTable 进行管理
同时标志位 has_sidetable_rc 改变
纯isa
通过 SideTable 管理
二、 Release
objc_object::rootRelease(bool performDealloc, objc_object::RRVariant variant)
{
// 不处理 TaggedPointer 直接 return
if (slowpath(isTaggedPointer())) return false;
...
retry:
do {
newisa = oldisa;
if (slowpath(!newisa.nonpointer)) {
// 非 nonpointer 通过 sidetable 处理
ClearExclusive(&isa.bits);
return sidetable_release(sideTableLocked, performDealloc);
}
...
// don't check newisa.fast_rr; we already called any RR overrides
uintptr_t carry;
newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry); // extra_rc--
if (slowpath(carry)) {
// don't ClearExclusive()
// extra_rc 见底 跳转执行 underflow
goto underflow;
}
} while (slowpath(!StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits)));
if (slowpath(newisa.isDeallocating()))
goto deallocate;
...
return false;
underflow:
// extra_rc 见底后,从 SideTable 拿回引用计数,或者销毁
// newisa.extra_rc-- underflowed: borrow from side table or deallocate
// abandon newisa to undo the decrement
newisa = oldisa;
if (slowpath(newisa.has_sidetable_rc)) {
// 如果有使用 SideTable
if (variant != RRVariant::Full) {
ClearExclusive(&isa.bits);
return rootRelease_underflow(performDealloc);
}
// Transfer retain count from side table to inline storage.
if (!sideTableLocked) {
ClearExclusive(&isa.bits);
sidetable_lock();
sideTableLocked = true;
// Need to start over to avoid a race against
// the nonpointer -> raw pointer transition.
oldisa = LoadExclusive(&isa.bits);
goto retry;
}
// 从 SideTable 移除引用计数
// Try to remove some retain counts from the side table.
auto borrow = sidetable_subExtraRC_nolock(RC_HALF);
bool emptySideTable = borrow.remaining == 0; // we'll clear the side table if no refcounts remain there
if (borrow.borrowed > 0) {
// Side table retain count decreased.
// Try to add them to the inline count.
bool didTransitionToDeallocating = false;
// 修改 extra_rc 及标志位
newisa.extra_rc = borrow.borrowed - 1; // redo the original decrement too
newisa.has_sidetable_rc = !emptySideTable;
...
}
else {
// Side table is empty after all. Fall-through to the dealloc path.
}
}
deallocate:
// Really deallocate.
// 销毁
...
if (performDealloc) {
((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(dealloc));
}
return true;
}