SideTables 相关

objc4-723.tar.gz

SideTables

// We cannot use a C++ static initializer to initialize SideTables because
// libc calls us before our C++ initializers run. We also don‘t want a global
// pointer to this struct because of the extra indirection.
// Do it the hard way.

// libc 比 C++ static initializer 先调用到 SideTables,所以不能用 C++ static initializer 去调用 SideTableInit ,所以才用 SideTableBuf 来初始化。

// alignas 字节对齐
// SideTableBuf 静态全局变量
alignas(StripedMap<SideTable>) static uint8_t 
    SideTableBuf[sizeof(StripedMap<SideTable>)];

static void SideTableInit() {
    new (SideTableBuf) StripedMap<SideTable>();
}

//reinterpret_cast C++ 里的强制类型转换符
static StripedMap<SideTable>& SideTables() {
    return *reinterpret_cast<StripedMap<SideTable>*>(SideTableBuf);
}
复制代码
// StripedMap<T> is a map of void* -> T, sized appropriately 
// for cache-friendly lock striping. 
// For example, this may be used as StripedMap<spinlock_t>
// or as StripedMap<SomeStruct> where SomeStruct stores a spin lock.
template<typename T>

// StripedMap<T> 是一个模板类,根据传递的实际参数决定其中 array 成员存储的元素类型。
// 能通过对象的地址,运算出 Hash 值,通过该 hash 值找到对应的 value 。

class StripedMap {

    enum { CacheLineSize = 64 };

#if TARGET_OS_EMBEDDED
    enum { StripeCount = 8 };
#else
    enum { StripeCount = 64 };
#endif

    struct PaddedT {
        T value alignas(CacheLineSize);
    };

    PaddedT array[StripeCount];

    // 哈希函数
    static unsigned int indexForPointer(const void *p) {
        uintptr_t addr = reinterpret_cast<uintptr_t>(p);
        return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
    }

 public:
    T& operator[] (const void *p) { 
        return array[indexForPointer(p)].value; 
    }
    const T& operator[] (const void *p) const { 
        return const_cast<StripedMap<T>>(this)[p]; 
    }
复制代码

SideTable

struct SideTable {
    // 保证原子操作的自旋锁
    spinlock_t slock;
    // 引用计数 hash 表
    RefcountMap refcnts;
    // 弱引用全局 hash 表
    weak_table_t weak_table;
    
    SideTable() {
        memset(&weak_table, 0, sizeof(weak_table));
    }

    ~SideTable() {
        _objc_fatal("Do not delete SideTable.");
    }

    void lock() { slock.lock(); }
    void unlock() { slock.unlock(); }
    void forceReset() { slock.forceReset(); }

    // Address-ordered lock discipline for a pair of side tables.

    template<HaveOld, HaveNew>
    static void lockTwo(SideTable *lock1, SideTable *lock2);
    template<HaveOld, HaveNew>
    static void unlockTwo(SideTable *lock1, SideTable *lock2);
};
复制代码

spinlock_t slock;

自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,适用于锁使用者保持锁时间比较短的情况。

深入理解 iOS 开发中的锁

自旋锁的实现原理

bool lock = false; // 一开始没有锁上,任何线程都可以申请锁  
do {  
    while(test_and_set(&lock); // test_and_set 是一个原子操作
        Critical section  // 临界区
    lock = false; // 相当于释放锁,这样别的线程可以进入临界区
        Reminder section // 不需要锁保护的代码        
}
复制代码

RefcountMap refcnts;

Objective-C 引用计数原理


weak_table_t weak_table;

/**
 * The global weak references table. Stores object ids as keys,
 * and weak_entry_t structs as their values.
 */
 
 // 使用全局的弱引用表
 // keys 对应 object ids
 // values 对应 weak_entry_t
 
struct weak_table_t {
    // 保存了所有指向 key 对应的对象的 weak 指针
    weak_entry_t *weak_entries;
    size_t    num_entries;
    uintptr_t mask;
    uintptr_t max_hash_displacement;
};
复制代码
weak_entry_t *weak_entries;
/*
The weak table is a hash table governed by a single spin lock.
An allocated blob of memory, most often an object, but under GC any such 
allocation, may have its address stored in a __weak marked storage location 
through use of compiler generated write-barriers or hand coded uses of the 
register weak primitive. Associated with the registration can be a callback 
block for the case when one of the allocated chunks of memory is reclaimed. 
The table is hashed on the address of the allocated memory.  When __weak 
marked memory changes its reference, we count on the fact that we can still 
see its previous reference.

So, in the hash table, indexed by the weakly referenced item, is a list of 
all locations where this address is currently being stored.
 
For ARC, we also keep track of whether an arbitrary object is being 
deallocated by briefly placing it in the table just prior to invoking 
dealloc, and removing it via objc_clear_deallocating just prior to memory 
reclamation.

*/

// The address of a __weak variable.
// These pointers are stored disguised so memory analysis tools
// don’t see lots of interior pointers from the weak table into objects.

// 
typedef DisguisedPtr<objc_object *> weak_referrer_t;

#if __LP64__
#define PTR_MINUS_2 62
#else
#define PTR_MINUS_2 30
#endif

/**
 * The internal structure stored in the weak references table. 
 * It maintains and stores
 * a hash set of weak references pointing to an object.
 * If out_of_line_ness != REFERRERS_OUT_OF_LINE then the set
 * is instead a small inline array.
 */
 
 // 当 out_of_line_ness != REFERRERS_OUT_OF_LINE 时, weak_referrer_t 则为 inline array
#define WEAK_INLINE_COUNT 4

// out_of_line_ness field overlaps with the low two bits of inline_referrers[1].
// inline_referrers[1] is a DisguisedPtr of a pointer-aligned address.
// The low two bits of a pointer-aligned DisguisedPtr will always be 0b00
// (disguised nil or 0x80..00) or 0b11 (any other address).
// Therefore out_of_line_ness == 0b10 is used to mark the out-of-line state.
#define REFERRERS_OUT_OF_LINE 2

struct weak_entry_t {
    // 被弱引用的对象
    DisguisedPtr<objc_object> referent;
    union {
        struct {
            weak_referrer_t *referrers;
            uintptr_t        out_of_line_ness : 2;
            uintptr_t        num_refs : PTR_MINUS_2;
            uintptr_t        mask;
            uintptr_t        max_hash_displacement;
        };
        struct {
            // out_of_line_ness field is low bits of inline_referrers[1]
            weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT];
        };
    };

    bool out_of_line() {
        return (out_of_line_ness == REFERRERS_OUT_OF_LINE);
    }

    weak_entry_t& operator=(const weak_entry_t& other) {
        memcpy(this, &other, sizeof(other));
        return *this;
    }
    
    // 默认是使用 inline_referrers 的方式来管理对象引用的,并把其余的位上的数据清空。
    weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
        : referent(newReferent)
    {
        inline_referrers[0] = newReferrer;
        for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
            inline_referrers[i] = nil;
        }
    }
};

复制代码
  • DisguisedPtr<objc_object> referent;
// DisguisedPtr<T> acts like pointer type T*, except the 
// stored value is disguised to hide it from tools like `leaks`.
// nil is disguised as itself so zero-filled memory works as expected, 
// which means 0x80..00 is also disguised as itself but we don‘t care.
// Note that weak_entry_t knows about this encoding.

// DisguisedPtr<T> 同 T* 的行为是一样的,只是为了避免被检测出内存泄漏
template <typename T>
class DisguisedPtr {
    // unsigned long
    uintptr_t value;

    static uintptr_t disguise(T* ptr) {
        return -(uintptr_t)ptr;
    }

    static T* undisguise(uintptr_t val) {
        return (T*)-val;
    }

    ...
};
复制代码
#ifndef _UINTPTR_T
#define _UINTPTR_T
typedef unsigned long		uintptr_t;
#endif /* _UINTPTR_T */
复制代码
  • weak_referrer_t *referrers;
  • weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
// objc_object**
typedef DisguisedPtr<objc_object *> weak_referrer_t;
复制代码
objc_initWeak

作为一个调用入口,当 newObj 存在时调用 storeWeak

/** 
 * Initialize a fresh weak pointer to some object location. 
 * It would be used for code like: 
 *
 * (The nil case) 
 * __weak id weakPtr;
 * (The non-nil case) 
 * NSObject *o = ...;
 * __weak id weakPtr = o;
 * 
 * This function IS NOT thread-safe with respect to concurrent 
 * modifications to the weak variable. (Concurrent weak clear is safe.) 
 * 并发修改时不是线程安全的
 *
 * @param location Address of __weak ptr. 弱引用指针的地址
 * @param newObj Object ptr. 对象指针
 */

id
objc_initWeak(id *location, id newObj)
{
    if (!newObj) {
        *location = nil;
        return nil;
    }

    return storeWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating>
        (location, (objc_object*)newObj);
}

objc_initWeakOrNil(id *location, id newObj)
{
    if (!newObj) {
        *location = nil;
        return nil;
    }

    return storeWeak<DontHaveOld, DoHaveNew, DontCrashIfDeallocating>
        (location, (objc_object*)newObj);
}
复制代码
storeWeak
// Update a weak variable.
// 更新弱引用指针的指向
// If HaveOld is true, the variable has an existing value 
//   that needs to be cleaned up. This value might be nil.
// HaveOld 为 true 时 变量有值,需要被及时清理,当前值可能为 nil
// If HaveNew is true, there is a new value that needs to be 
//   assigned into the variable. This value might be nil.
// HaveNew 为 true 时 变量有值,需要被及时分配,当前值可能为 nil
// If CrashIfDeallocating is true, the process is halted if newObj is 
//   deallocating or newObj’s class does not support weak references. 
//   If CrashIfDeallocating is false, nil is stored instead.
// CrashIfDeallocating 为 true 时,说明 newObj 在释放中或不支持弱引用,这个过程将会被停止;为 false 时,将用 nil 替代存储

enum CrashIfDeallocating {
    DontCrashIfDeallocating = false, DoCrashIfDeallocating = true
};
template <HaveOld haveOld, HaveNew haveNew,
          CrashIfDeallocating crashIfDeallocating>
static id 
storeWeak(id *location, objc_object *newObj)
{
    assert(haveOld  ||  haveNew);
    if (!haveNew) assert(newObj == nil);

    Class previouslyInitializedClass = nil;
    id oldObj;
    SideTable *oldTable;
    SideTable *newTable;

    // Acquire locks for old and new values.
    // Order by lock address to prevent lock ordering problems. 
    // Retry if the old value changes underneath us.
    
    // 通过对象的地址从 SideTables 中取出对应的 SideTable
 retry:
    if (haveOld) {
        oldObj = *location;
        oldTable = &SideTables()[oldObj];
    } else {
        oldTable = nil;
    }
    if (haveNew) {
        newTable = &SideTables()[newObj];
    } else {
        newTable = nil;
    }

    // 加锁管理一对 side tables
    SideTable::lockTwo<haveOld, haveNew>(oldTable, newTable);

    if (haveOld  &&  *location != oldObj) {
        // 当前 *location != oldObj,说明 oldObj 已经处理过(haveOld 为 true),但是又被其他线程修改
        SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
        goto retry;
    }

    // Prevent a deadlock between the weak reference machinery
    // and the +initialize machinery by ensuring that no 
    // weakly-referenced object has an un-+initialized isa.
    
    // 保证弱引用对象的 isa 都被初始化,防止弱引用和 +initialize 之间发生死锁,也就是避免 +initialize 中调用了 storeWeak 方法,而在 storeWeak 方法中 weak_register_no_lock 方法中用到对象的 isa 还没有初始化完成的情况
    if (haveNew  &&  newObj) {
        Class cls = newObj->getIsa();
        // isa 非空但未初始化完成
        if (cls != previouslyInitializedClass  &&  
            !((objc_class *)cls)->isInitialized()) 
        {
            SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
            // 发送 +initialize 消息到未初始化的类
            _class_initialize(_class_getNonMetaClass(cls, (id)newObj));

            // If this class is finished with +initialize then we‘re good.
            // 理想情况下已经初始化完成,也就是不会进入这里面
            // If this class is still running +initialize on this thread 
            // (i.e. +initialize called storeWeak on an instance of itself)
            // then we may proceed but it will appear initializing and 
            // not yet initialized to the check above.
            // Instead set previouslyInitializedClass to recognize it on retry.
            // 如果该类还没有初始化完成,例如在 +initialize 中调用了 storeWeak 方法,也就是会进入这里面,进而设置  previouslyInitializedClass  以在重试时识别它
            previouslyInitializedClass = cls;
            
            // 重试
            goto retry;
        }
    }

    // Clean up old value, if any.
    // 清除旧值 1️⃣
    if (haveOld) {
        weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
    }

    // Assign new value, if any.
    // 分配新值 2️⃣
    if (haveNew) {
        newObj = (objc_object *)
            weak_register_no_lock(&newTable->weak_table, (id)newObj, location, 
                                  crashIfDeallocating);
        // weak_register_no_lock returns nil if weak store should be rejected

        // Set is-weakly-referenced bit in refcount table.
        // 在引用计数表中设置标志位
        if (newObj  &&  !newObj->isTaggedPointer()) {
            newObj->setWeaklyReferenced_nolock();
        }

        // Do not set *location anywhere else. That would introduce a race.
        *location = (id)newObj;
    }
    else {
        // No new value. The storage is not changed.
    }
    
    SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);

    return (id)newObj;
}
复制代码
weak_unregister_no_lock 1️⃣
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
复制代码
/** 
 * Unregister an already-registered weak reference.
 * 解除已注册的 对象-弱引用指针 对
 * This is used when referrer‘s storage is about to go away, but referent
 * isn’t dead yet. (Otherwise, zeroing referrer later would be a
 * bad memory access.)
 * Does nothing if referent/referrer is not a currently active weak reference.
 * Does not zero referrer.
 * 
 * FIXME currently requires old referent value to be passed in (lame)
 * FIXME unregistration should be automatic if referrer is collected
 * 
 * @param weak_table The global weak table. 全局弱引用表
 * @param referent The object. 弱引用所指向的对象
 * @param referrer The weak reference. 弱引用指针地址
 */
void
weak_unregister_no_lock(weak_table_t *weak_table, id referent_id, 
                        id *referrer_id)
{
    // 使用指针访问
    objc_object *referent = (objc_object *)referent_id;
    objc_object **referrer = (objc_object **)referrer_id;

    weak_entry_t *entry;
    
    // referent 为 nil 时直接返回
    if (!referent) return;

    // 通过弱引用所指向的对象在 weak_table 找到对应的 entry
    if ((entry = weak_entry_for_referent(weak_table, referent))) {
        // 从 entry 中移除 referrer
        remove_referrer(entry, referrer);
        // 判断 entry 在移除操作后是否为空
        bool empty = true;
        if (entry->out_of_line()  &&  entry->num_refs != 0) {
            empty = false;
        }
        else {
            for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
                if (entry->inline_referrers[i]) {
                    empty = false; 
                    break;
                }
            }
        }

        if (empty) {
            // 从 weak_table 中移除 entry
            weak_entry_remove(weak_table, entry);
        }
    }

    // Do not set *referrer = nil. objc_storeWeak() requires that the 
    // value not change.
}
复制代码
weak_entry_for_referent(weak_table, referent)
/** 
 * Return the weak reference table entry for the given referent. 
 * If there is no entry for referent, return NULL. 
 * Performs a lookup.
 *
 * 在 weak_table 中进行查找,返回对应的 entry,没有则返回 NULL
 *
 * @param weak_table 
 * @param referent The object. Must not be nil.
 * 
 * @return The table of weak referrers to this object. 
 */
static weak_entry_t *
weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)
{
    // 不能为 nil
    assert(referent);

    weak_entry_t *weak_entries = weak_table->weak_entries;

    if (!weak_entries) return nil;

    // hash_pointer 哈希函数 传入的是 objc_object *key
    // mask 计数辅助量❓
    // hash_displacement 移位的次数❓
    size_t begin = hash_pointer(referent) & weak_table->mask;
    size_t index = begin;
    size_t hash_displacement = 0;
    // 处理冲突
    while (weak_table->weak_entries[index].referent != referent) {
        index = (index+1) & weak_table->mask;
        if (index == begin) bad_weak_table(weak_table->weak_entries);
        hash_displacement++;
        if (hash_displacement > weak_table->max_hash_displacement) {
            return nil;
        }
    }
    
    return &weak_table->weak_entries[index];
}
复制代码
remove_referrer
/** 
 * Remove old_referrer from set of referrers, if it‘s present.
 * 从 referrers 或 inline_referrers 中移除 old_referrer
 * Does not remove duplicates, because duplicates should not exist. 
 * 不移除重复值,因为其不应存在
 * 
 * @todo this is slow if old_referrer is not present. Is this ever the case? 
 *
 * @param entry The entry holding the referrers.
 * @param old_referrer The referrer to remove. 
 */
static void remove_referrer(weak_entry_t *entry, objc_object **old_referrer)
{
    // 判断 out_of_line_ness 是否等于 REFERRERS_OUT_OF_LINE
    // 不相等时,weak_entry_t 内部使用的 struct 是 inline_referrers
    // WEAK_INLINE_COUNT 4
    if (! entry->out_of_line()) {
        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
            if (entry->inline_referrers[i] == old_referrer) {
                entry->inline_referrers[i] = nil;
                return;
            }
        }
        // 打印错误信息
        _objc_inform("Attempted to unregister unknown __weak variable "
                     "at %p. This is probably incorrect use of "
                     "objc_storeWeak() and objc_loadWeak(). "
                     "Break on objc_weak_error to debug.\n", 
                     old_referrer);
        objc_weak_error();
        return;
    }

    // 当 referrer 超过 WEAK_INLINE_COUNT 也就是多于3个时,weak_entry_t 使用 referrers
    // 算出哈希值
    // w_hash_pointer 哈希函数 传入的是 objc_object **key
    size_t begin = w_hash_pointer(old_referrer) & (entry->mask);
    size_t index = begin;
    size_t hash_displacement = 0;
    while (entry->referrers[index] != old_referrer) {
        index = (index+1) & entry->mask;
        // 错误处理
        if (index == begin) bad_weak_table(entry);
        // hash_displacement 移位的次数❓
        hash_displacement++;
        // 错误处理
        if (hash_displacement > entry->max_hash_displacement) {
            _objc_inform("Attempted to unregister unknown __weak variable "
                         "at %p. This is probably incorrect use of "
                         "objc_storeWeak() and objc_loadWeak(). "
                         "Break on objc_weak_error to debug.\n", 
                         old_referrer);
            objc_weak_error();
            return;
        }
    }
    // 置为 nil
    entry->referrers[index] = nil;
    entry->num_refs--;
}
复制代码
weak_register_no_lock 2️⃣
newObj = (objc_object *)
            weak_register_no_lock(&newTable->weak_table, (id)newObj, location, 
                                  crashIfDeallocating);
复制代码
/** 
 * Registers a new (object, weak pointer) pair. Creates a new weak
 * object entry if it does not exist.
 * 注册新的 对象-弱引用指针 对,如果没有对应的 entry 则重新创建一个 entry
 * 
 * @param weak_table The global weak table. 全局弱引用表
 * @param referent The object pointed to by the weak reference. 弱引用所指向的对象
 * @param referrer The weak pointer address. 弱引用指针地址
 */
id 
weak_register_no_lock(weak_table_t *weak_table, id referent_id, 
                      id *referrer_id, bool crashIfDeallocating)
{
    // 使用指针访问
    objc_object *referent = (objc_object *)referent_id;
    objc_object **referrer = (objc_object **)referrer_id;

    // 检测对象是否存在,是否使用 tagged pointer
    if (!referent  ||  referent->isTaggedPointer()) return referent_id;

    // ensure that the referenced object is viable
    // 确保引用的对象时存在的
    bool deallocating;
    if (!referent->ISA()->hasCustomRR()) {
        // 对象没有自定义的内存管理方法,直接通过 rootIsDeallocating 方法看是否被释放
        deallocating = referent->rootIsDeallocating();
    }
    else {
        // ❓
        BOOL (*allowsWeakReference)(objc_object *, SEL) = 
            (BOOL(*)(objc_object *, SEL))
            object_getMethodImplementation((id)referent, 
                                           SEL_allowsWeakReference);
        if ((IMP)allowsWeakReference == _objc_msgForward) {
            return nil;
        }
        deallocating =
            ! (*allowsWeakReference)(referent, SEL_allowsWeakReference);
    }

    // 被释放
    if (deallocating) {
        if (crashIfDeallocating) {
            // 打印消息
            _objc_fatal("Cannot form weak reference to instance (%p) of "
                        "class %s. It is possible that this object was "
                        "over-released, or is in the process of deallocation.",
                        (void*)referent, object_getClassName((id)referent));
        } else {
            return nil;
        }
    }

    // now remember it and where it is being stored
    weak_entry_t *entry;
    // 通过弱引用所指向的对象在 weak_table 找到对应的 entry
    if ((entry = weak_entry_for_referent(weak_table, referent))) {
        // 在 entry 中添加弱引用指针地址
        append_referrer(entry, referrer);
    } 
    else {
        // 没能找到对应的 entry,创建 new_entry
        weak_entry_t new_entry(referent, referrer);
        // 弱引用表满容,进行自增长
        weak_grow_maybe(weak_table);
        // 默认是使用 inline_referrers,直接进行插入
        weak_entry_insert(weak_table, &new_entry);
    }

    // Do not set *referrer. objc_storeWeak() requires that the 
    // value not change.
    // storeWeak 中还会需要到 *referrer,所以不在其他地方改变 *referrer

    return referent_id;
}

复制代码
append_referrer
/** 
 * Add the given referrer to set of weak pointers in this entry.
 * Does not perform duplicate checking (b/c weak pointers are never
 * added to a set twice). 
 *
 * @param entry The entry holding the set of weak pointers. 
 * @param new_referrer The new weak pointer to be added.
 */
static void append_referrer(weak_entry_t *entry, objc_object **new_referrer)
{
    // 判断 out_of_line_ness 是否等于 REFERRERS_OUT_OF_LINE
    // 不相等时,weak_entry_t 内部使用的 struct 是 inline_referrers
    // WEAK_INLINE_COUNT 4
    if (! entry->out_of_line()) {
        // Try to insert inline.
        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
            if (entry->inline_referrers[i] == nil) {
                entry->inline_referrers[i] = new_referrer;
                return;
            }
        }

        // Couldn’t insert inline. Allocate out of line.
        // 当 referrer 超过 WEAK_INLINE_COUNT 也就是多于3个时,weak_entry_t 使用 referrers
        weak_referrer_t *new_referrers = (weak_referrer_t *)
            calloc(WEAK_INLINE_COUNT, sizeof(weak_referrer_t));
        // This constructed table is invalid, but grow_refs_and_insert
        // will fix it and rehash it.
        // 这里构造的表示无效的,通过后面的 grow_refs_and_insert 修复
        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
            new_referrers[i] = entry->inline_referrers[i];
        }
        entry->referrers = new_referrers;
        entry->num_refs = WEAK_INLINE_COUNT;
        entry->out_of_line_ness = REFERRERS_OUT_OF_LINE;
        entry->mask = WEAK_INLINE_COUNT-1;
        entry->max_hash_displacement = 0;
    }

    assert(entry->out_of_line());
    
    // #define TABLE_SIZE(entry) (entry->mask ? entry->mask + 1 : 0)
    // 也就是 entry->num_refs >= 3
    if (entry->num_refs >= TABLE_SIZE(entry) * 3/4) {
        // 将前面构造的表转换为哈希表
        return grow_refs_and_insert(entry, new_referrer);
    }
    
    // 添加 new_referrer 到 referrers
    // w_hash_pointer 哈希函数 传入的是 objc_object **key
    size_t begin = w_hash_pointer(new_referrer) & (entry->mask);
    size_t index = begin;
    size_t hash_displacement = 0;
    while (entry->referrers[index] != nil) {
        hash_displacement++;
        index = (index+1) & entry->mask;
        // bad_weak_table 打印消息
        if (index == begin) bad_weak_table(entry);
    }
    if (hash_displacement > entry->max_hash_displacement) {
        entry->max_hash_displacement = hash_displacement;
    }
    weak_referrer_t &ref = entry->referrers[index];
    ref = new_referrer;
    entry->num_refs++;
}
复制代码
grow_refs_and_insert
/** 
 * Grow the entry’s hash table of referrers. Rehashes each
 * of the referrers.
 * 扩展为一个哈希表, Rehashes 通过前面的 append_referrer 完成
 * 
 * @param entry Weak pointer hash set for a particular object.
 */
__attribute__((noinline, used))
static void grow_refs_and_insert(weak_entry_t *entry, 
                                 objc_object **new_referrer)
{
    assert(entry->out_of_line());

    size_t old_size = TABLE_SIZE(entry);
    size_t new_size = old_size ? old_size * 2 : 8;

    size_t num_refs = entry->num_refs;
    weak_referrer_t *old_refs = entry->referrers;
    entry->mask = new_size - 1;
    
    entry->referrers = (weak_referrer_t *)
        calloc(TABLE_SIZE(entry), sizeof(weak_referrer_t));
    entry->num_refs = 0;
    entry->max_hash_displacement = 0;
    
    for (size_t i = 0; i < old_size && num_refs > 0; i++) {
        if (old_refs[i] != nil) {
            append_referrer(entry, old_refs[i]);
            num_refs--;
        }
    }
    // Insert
    // 将弱引用指针添加进去
    append_referrer(entry, new_referrer);
    if (old_refs) free(old_refs);
}
复制代码

转载于:https://juejin.im/post/5b72c0e0e51d4566877c0cac

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值