I am reading code of objc from https://github.com/opensource-apple/objc4.
In the code, there is a struct SideTable, which contains reference count of corresponding object and a weak_table_t.
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
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(); }
bool trylock() { return slock.trylock(); }
// Address-ordered lock discipline for a pair of side tables.
template<bool HaveOld, bool HaveNew>
static void lockTwo(SideTable *lock1, SideTable *lock2);
template<bool HaveOld, bool HaveNew>
static void unlockTwo(SideTable *lock1, SideTable *lock2);
};
And the SideTable of an object can be retrieved by SideTables()[obj] as the SideTable of every object is stored in a StripedMap, which is actually an array using the hash value of an object's address as index.
But according to the code of weak_entry_for_referent, the runtime gets the weak_entry_t of a referent through checking weak_table->weak_entries[index].referent.
static weak_entry_t *
weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)
{
assert(referent);
weak_entry_t *weak_entries = weak_table->weak_entries;
if (!weak_entries) return nil;
size_t index = hash_pointer(referent) & weak_table->mask;
size_t hash_displacement = 0;
while (weak_table->weak_entries[index].referent != referent) {
index = (index+1) & weak_table->mask;
hash_displacement++;
if (hash_displacement > weak_table->max_hash_displacement) {
return nil;
}
}
return &weak_table->weak_entries[index];
}
It means the weak_table contains more than the weak entries for a single object. Then why is weak_table_t a member of SideTable instead of a global data?
As I can't find code which really initialize SideTable of object (storeStrong just use the SideTable without initializing it at first) and weak_table, I can't quite understand how things work in the background.
Can anybody give me a hint?