Swift源码解析之弱引用

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

调用 RefCounts 的 increment 方法:


void increment(uint32_t inc = 1) {
 // 3. 原子地读出 InlineRefCountBits 对象(即一个 uint64_t)。
 auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
 RefCountBits newbits;
 do {
 newbits = oldbits;
 // 4. 调用 InlineRefCountBits 的 incrementStrongExtraRefCount 方法
 // 对这个 uint64_t 进行一系列运算。
 bool fast = newbits.incrementStrongExtraRefCount(inc);
 // 无 weak、unowned 引用时一般不会进入。
 if (SWIFT_UNLIKELY(!fast)) {
  if (oldbits.isImmortal())
  return;
  return incrementSlow(oldbits, inc);
 }
 // 5. 通过 CAS 将运算后的 uint64_t 设置回去。
 } while (!refCounts.compare_exchange_weak(oldbits, newbits,
           std::memory_order_relaxed));
}

到这里就完成了一次 retain 操作。

SideTableRefCountBits

上面是不存在 weak、unowned 引用的情况,现在我们来看看增加一个 weak 引用会怎样。

  1. 调用 SIL 接口 swift::swift_weakAssign(暂时省略这块的逻辑,它属于引用者的逻辑,我们现在先分析被引用者)
  2. 调用 RefCounts<InlineRefCountBits>::formWeakReference 增加一个弱引用:

template <>
HeapObjectSideTableEntry* RefCounts<InlineRefCountBits>::formWeakReference()
{
 // 分配一个 Side Table。
 auto side = allocateSideTable(true);
 if (side)
 // 增加一个弱引用。
 return side->incrementWeak();
 else
 return nullptr;
}

重点来看一下 allocateSideTable 的实现:


template <>
HeapObjectSideTableEntry* RefCounts<InlineRefCountBits>::allocateSideTable(bool failIfDeiniting)
{
 auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);

 // 已有 Side Table 或正在析构就直接返回。
 if (oldbits.hasSideTable()) {
 return oldbits.getSideTable();
 } 
 else if (failIfDeiniting && oldbits.getIsDeiniting()) {
 return nullptr;
 }

 // 分配 Side Table 对象。
 HeapObjectSideTableEntry *side = new HeapObjectSideTableEntry(getHeapObject());

 auto newbits = InlineRefCountBits(side);

 do {
 if (oldbits.hasSideTable()) {
  // 此时可能其他线程创建了 Side Table,删除该线程分配的,然后返回。
  auto result = oldbits.getSideTable();
  delete side;
  return result;
 }
 else if (failIfDeiniting && oldbits.getIsDeiniting()) {
  return nullptr;
 }

 // 用当前的 InlineRefCountBits 初始化 Side Table。
 side->initRefCounts(oldbits);
 // 进行 CAS。
 } while (! refCounts.compare_exchange_weak(oldbits, newbits,
            std::memory_order_release,
            std::memory_order_relaxed));
 return side;
}