Swift源码解析之弱引用

2020-01-09 00:12:25王冬梅

还记得 HeapObject 里的 RefCounts 实际上是 InlineRefCountBits 的一个 wrapper 吗?上面构造完 Side Table 以后,对象中的 InlineRefCountBits 就不是原来的引用计数了,而是一个指向 Side Table 的指针,然而由于它们实际都是 uint64_t,因此需要一个方法来区分。区分的方法我们可以来看 InlineRefCountBits 的构造函数:


LLVM_ATTRIBUTE_ALWAYS_INLINE
 RefCountBitsT(HeapObjectSideTableEntry* side)
 : bits((reinterpret_cast<BitsType>(side) >> Offsets::SideTableUnusedLowBits)
   | (BitsType(1) << Offsets::UseSlowRCShift)
   | (BitsType(1) << Offsets::SideTableMarkShift))
 {
 assert(refcountIsInline);
 }

其实还是最常见的方法,把指针地址无用的位替换成标识位。

顺便,看一下 Side Table 的结构:


class HeapObjectSideTableEntry {
 // FIXME: does object need to be atomic?
 std::atomic<HeapObject*> object;
 SideTableRefCounts refCounts;

 public:
 HeapObjectSideTableEntry(HeapObject *newObject)
 : object(newObject), refCounts()
 { }

 // ...

};

此时再增加引用计数会怎样呢?来看下之前的 RefCounts::increment 方法:


void increment(uint32_t inc = 1) {
 auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
 RefCountBits newbits;
 do {
 newbits = oldbits;
 bool fast = newbits.incrementStrongExtraRefCount(inc);
 // ---> 这次进入这个分支。
 if (SWIFT_UNLIKELY(!fast)) {
  if (oldbits.isImmortal())
  return;
  return incrementSlow(oldbits, inc);
 }
 } while (!refCounts.compare_exchange_weak(oldbits, newbits,
           std::memory_order_relaxed));
}
template <typename RefCountBits>
void RefCounts<RefCountBits>::incrementSlow(RefCountBits oldbits,
           uint32_t n) {
 if (oldbits.isImmortal()) {
 return;
 }
 else if (oldbits.hasSideTable()) {
 auto side = oldbits.getSideTable();
 // ---> 然后调用到这里。
 side->incrementStrong(n);
 }
 else {
 swift::swift_abortRetainOverflow();
 }
}
void HeapObjectSideTableEntry::incrementStrong(uint32_t inc) {
 // 最终到这里,refCounts 是一个 RefCounts<SideTableRefCountBits> 对象。
 refCounts.increment(inc);
}

到这里我们就需要引出 SideTableRefCountBits 了,它与前面的 InlineRefCountBits 很像,只不过又多了一个字段,看一下定义: