iOS底层系列02--objc_object与objc_clas
2021-02-03 本文已影响0人
YanZi_33
- 在objc4的源码中有这么几个常见的结构体:
struct objc_object
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA(bool authenticated = false);
// rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
Class rawISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
uintptr_t isaBits() const;
// initIsa() should be used to init the isa of new objects only.
// If this object already has an isa, use changeIsa() for correctness.
// initInstanceIsa(): objects with no custom RR/AWZ
// initClassIsa(): class objects
// initProtocolIsa(): protocol objects
// initIsa(): other objects
void initIsa(Class cls /*nonpointer=false*/);
void initClassIsa(Class cls /*nonpointer=maybe*/);
void initProtocolIsa(Class cls /*nonpointer=maybe*/);
void initInstanceIsa(Class cls, bool hasCxxDtor);
// changeIsa() should be used to change the isa of existing objects.
// If this is a new object, use initIsa() for performance.
Class changeIsa(Class newCls);
//指针优化与带标记的指针小对象
bool hasNonpointerIsa();
bool isTaggedPointer();
bool isTaggedPointerOrNil();
bool isBasicTaggedPointer();
bool isExtTaggedPointer();
bool isClass();
// object may have associated objects?
//关联对象
bool hasAssociatedObjects();
void setHasAssociatedObjects();
// object may be weakly referenced?
//对象的弱引用指针
bool isWeaklyReferenced();
void setWeaklyReferenced_nolock();
// object may have -.cxx_destruct implementation?
bool hasCxxDtor();
// Optimized calls to retain/release methods
//以下是内存管理相关的函数
id retain();
void release();
id autorelease();
// Implementations of retain/release methods
id rootRetain();
bool rootRelease();
id rootAutorelease();
bool rootTryRetain();
bool rootReleaseShouldDealloc();
uintptr_t rootRetainCount();
// Implementation of dealloc methods
bool rootIsDeallocating();
void clearDeallocating();
void rootDealloc();
private:
void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
// Slow paths for inline control
id rootAutorelease2();
uintptr_t overrelease_error();
#if SUPPORT_NONPOINTER_ISA
// Controls what parts of root{Retain,Release} to emit/inline
// - Full means the full (slow) implementation
// - Fast means the fastpaths only
// - FastOrMsgSend means the fastpaths but checking whether we should call
// -retain/-release or Swift, for the usage of objc_{retain,release}
enum class RRVariant {
Full,
Fast,
FastOrMsgSend,
};
// Unified retain count manipulation for nonpointer isa
inline id rootRetain(bool tryRetain, RRVariant variant);
inline bool rootRelease(bool performDealloc, RRVariant variant);
id rootRetain_overflow(bool tryRetain);
uintptr_t rootRelease_underflow(bool performDealloc);
void clearDeallocating_slow();
// Side table retain count overflow for nonpointer isa
struct SidetableBorrow { size_t borrowed, remaining; };
void sidetable_lock();
void sidetable_unlock();
void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
bool sidetable_addExtraRC_nolock(size_t delta_rc);
SidetableBorrow sidetable_subExtraRC_nolock(size_t delta_rc);
size_t sidetable_getExtraRC_nolock();
void sidetable_clearExtraRC_nolock();
#endif
// Side-table-only retain count
// 内存关联的底层数据结构 -- 散列表
bool sidetable_isDeallocating();
void sidetable_clearDeallocating();
bool sidetable_isWeaklyReferenced();
void sidetable_setWeaklyReferenced_nolock();
id sidetable_retain(bool locked = false);
id sidetable_retain_slow(SideTable& table);
uintptr_t sidetable_release(bool locked = false, bool performDealloc = true);
uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
bool sidetable_tryRetain();
uintptr_t sidetable_retainCount();
#if DEBUG
bool sidetable_present();
#endif
};
-
isa成员
:OC对象的isa指针; -
Class ISA(bool authenticated = false)
:获取obj的isa指针所指向的class,必须保证obj不是taggedPonter对象;
inline Class objc_object::ISA(bool authenticated){
//断言 若传入TaggedPointer对象 会崩溃
ASSERT(!isTaggedPointer());
return isa.getDecodedClass(authenticated);
}
-
Class rawISA()
:获取obj的isa指针所指向的class,必须保证obj不是taggedPonter对象或者obj是nonpointer,即isa指针经过优化的;
inline Class objc_object::rawISA(){
//断言 必须为非taggedPonter对象或isa指针经过优化
ASSERT(!isTaggedPointer() && !isa.nonpointer);
return (Class)isa.bits;
}
-
Class getIsa()
:获取obj的isa指针;
inline Class objc_object::getIsa() {
if (fastpath(!isTaggedPointer())) return ISA();
extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
uintptr_t slot, ptr = (uintptr_t)this;
Class cls;
slot = (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
cls = objc_tag_classes[slot];
if (slowpath(cls == (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer)) {
slot = (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
cls = objc_tag_ext_classes[slot];
}
return cls;
}
-
大概率执行
if (fastpath(!isTaggedPointer())) return ISA()
; -
允许传入TaggedPointer对象;
-
初始化isa指针有以下几个函数:
-
void initIsa(Class cls /*nonpointer=false*/)
-
void initClassIsa(Class cls /*nonpointer=maybe*/)
-
void initProtocolIsa(Class cls /*nonpointer=maybe*/)
-
void initInstanceIsa(Class cls, bool hasCxxDtor)
-
最终都会执行下面的函数实现:
inline void objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor){
//必须保证obj是非标记指针的OC对象
ASSERT(!isTaggedPointer());
isa_t newisa(0);
if (!nonpointer) {
newisa.setClass(cls, this);
} else {
ASSERT(!DisableNonpointerIsa);
ASSERT(!cls->instancesRequireRawIsa());
#if SUPPORT_INDEXED_ISA
ASSERT(cls->classArrayIndex() > 0);
newisa.bits = ISA_INDEX_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
newisa.bits = ISA_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
# if ISA_HAS_CXX_DTOR_BIT
newisa.has_cxx_dtor = hasCxxDtor;
# endif
newisa.setClass(cls, this);
#endif
newisa.extra_rc = 1;
}
// This write must be performed in a single store in some cases
// (for example when realizing a class because other threads
// may simultaneously try to use the class).
// fixme use atomics here to guarantee single-store and to
// guarantee memory order w.r.t. the class index table
// ...but not too atomic because we don't want to hurt instantiation
isa = newisa;
}
-
Class changeIsa(Class newCls)
: 更改对象的isa指针指向,本质是改变对象所属的类class,与KVO的底层实现类似; - 其他部分详细内容见源码注释;
struct objc_class
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
//Class ISA;
//父类指针
Class superclass;
//缓存 -- 主要做方法缓存
cache_t cache; // formerly cache pointer and vtable
//存储类信息的结构体
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
Class getSuperclass() const {}
void setSuperclass(Class newSuperclass) {}
//获取类的数据
class_rw_t *data() const {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
void setInfo(uint32_t set) {
ASSERT(isFuture() || isRealized());
data()->setFlags(set);
}
void clearInfo(uint32_t clear) {
ASSERT(isFuture() || isRealized());
data()->clearFlags(clear);
}
// set and clear must not overlap
void changeInfo(uint32_t set, uint32_t clear) {
ASSERT(isFuture() || isRealized());
ASSERT((set & clear) == 0);
data()->changeFlags(set, clear);
}
//是否有自定义的内存管理方法
#if FAST_HAS_DEFAULT_RR
bool hasCustomRR() const {
return !bits.getBit(FAST_HAS_DEFAULT_RR);
}
void setHasDefaultRR() {
bits.setBits(FAST_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
bits.clearBits(FAST_HAS_DEFAULT_RR);
}
#else
bool hasCustomRR() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_RR);
}
void setHasDefaultRR() {
bits.data()->setFlags(RW_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
bits.data()->clearFlags(RW_HAS_DEFAULT_RR);
}
#endif
//是否有自定义的allocWithZone方法
#if FAST_CACHE_HAS_DEFAULT_AWZ
bool hasCustomAWZ() const {
return !cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
void setHasDefaultAWZ() {
cache.setBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
cache.clearBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
#else
bool hasCustomAWZ() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_AWZ);
}
void setHasDefaultAWZ() {
bits.data()->setFlags(RW_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
bits.data()->clearFlags(RW_HAS_DEFAULT_AWZ);
}
#endif
//是否有对象构造,初始化的核心方法
#if FAST_CACHE_HAS_DEFAULT_CORE
bool hasCustomCore() const {
return !cache.getBit(FAST_CACHE_HAS_DEFAULT_CORE);
}
void setHasDefaultCore() {
return cache.setBit(FAST_CACHE_HAS_DEFAULT_CORE);
}
void setHasCustomCore() {
return cache.clearBit(FAST_CACHE_HAS_DEFAULT_CORE);
}
#else
bool hasCustomCore() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_CORE);
}
void setHasDefaultCore() {
bits.data()->setFlags(RW_HAS_DEFAULT_CORE);
}
void setHasCustomCore() {
bits.data()->clearFlags(RW_HAS_DEFAULT_CORE);
}
#endif
//对象的C++方法
#if FAST_CACHE_HAS_CXX_DTOR
bool hasCxxDtor() {
ASSERT(isRealized());
return cache.getBit(FAST_CACHE_HAS_CXX_DTOR);
}
void setHasCxxDtor() {
cache.setBit(FAST_CACHE_HAS_CXX_DTOR);
}
#else
bool hasCxxDtor() {
ASSERT(isRealized());
return bits.data()->flags & RW_HAS_CXX_DTOR;
}
void setHasCxxDtor() {
bits.data()->setFlags(RW_HAS_CXX_DTOR);
}
#endif
//对象的isa指针
//RAW_ISA --> 非TaggedPointer且isa优化过的OC对象
#if FAST_CACHE_REQUIRES_RAW_ISA
bool instancesRequireRawIsa() {
return cache.getBit(FAST_CACHE_REQUIRES_RAW_ISA);
}
void setInstancesRequireRawIsa() {
cache.setBit(FAST_CACHE_REQUIRES_RAW_ISA);
}
#elif SUPPORT_NONPOINTER_ISA
bool instancesRequireRawIsa() {
return bits.data()->flags & RW_REQUIRES_RAW_ISA;
}
void setInstancesRequireRawIsa() {
bits.data()->setFlags(RW_REQUIRES_RAW_ISA);
}
#else
bool instancesRequireRawIsa() {
return true;
}
void setInstancesRequireRawIsa() {
// nothing
}
#endif
void setInstancesRequireRawIsaRecursively(bool inherited = false);
void printInstancesRequireRawIsa(bool inherited);
#if CONFIG_USE_PREOPT_CACHES
bool allowsPreoptCaches() const {
return !(bits.data()->flags & RW_NOPREOPT_CACHE);
}
bool allowsPreoptInlinedSels() const {
return !(bits.data()->flags & RW_NOPREOPT_SELS);
}
void setDisallowPreoptCaches() {
bits.data()->setFlags(RW_NOPREOPT_CACHE | RW_NOPREOPT_SELS);
}
void setDisallowPreoptInlinedSels() {
bits.data()->setFlags(RW_NOPREOPT_SELS);
}
void setDisallowPreoptCachesRecursively(const char *why);
void setDisallowPreoptInlinedSelsRecursively(const char *why);
#else
bool allowsPreoptCaches() const { return false; }
bool allowsPreoptInlinedSels() const { return false; }
void setDisallowPreoptCaches() { }
void setDisallowPreoptInlinedSels() { }
void setDisallowPreoptCachesRecursively(const char *why) { }
void setDisallowPreoptInlinedSelsRecursively(const char *why) { }
#endif
bool canAllocNonpointer() {
ASSERT(!isFuture());
return !instancesRequireRawIsa();
}
bool isSwiftStable() {
return bits.isSwiftStable();
}
bool isSwiftLegacy() {
return bits.isSwiftLegacy();
}
bool isAnySwift() {
return bits.isAnySwift();
}
bool isSwiftStable_ButAllowLegacyForNow() {
return bits.isSwiftStable_ButAllowLegacyForNow();
}
uint32_t swiftClassFlags() {
return *(uint32_t *)(&bits + 1);
}
bool usesSwiftRefcounting() {
if (!isSwiftStable()) return false;
return bool(swiftClassFlags() & 2); //ClassFlags::UsesSwiftRefcounting
}
bool canCallSwiftRR() {
// !hasCustomCore() is being used as a proxy for isInitialized(). All
// classes with Swift refcounting are !hasCustomCore() (unless there are
// category or swizzling shenanigans), but that bit is not set until a
// class is initialized. Checking isInitialized requires an extra
// indirection that we want to avoid on RR fast paths.
//
// In the unlikely event that someone causes a class with Swift
// refcounting to be hasCustomCore(), we'll fall back to sending -retain
// or -release, which is still correct.
return !hasCustomCore() && usesSwiftRefcounting();
}
bool isStubClass() const {
uintptr_t isa = (uintptr_t)isaBits();
return 1 <= isa && isa < 16;
}
// Swift stable ABI built for old deployment targets looks weird.
// The is-legacy bit is set for compatibility with old libobjc.
// We are on a "new" deployment target so we need to rewrite that bit.
// These stable-with-legacy-bit classes are distinguished from real
// legacy classes using another bit in the Swift data
// (ClassFlags::IsSwiftPreStableABI)
bool isUnfixedBackwardDeployingStableSwift() {
// Only classes marked as Swift legacy need apply.
if (!bits.isSwiftLegacy()) return false;
// Check the true legacy vs stable distinguisher.
// The low bit of Swift's ClassFlags is SET for true legacy
// and UNSET for stable pretending to be legacy.
bool isActuallySwiftLegacy = bool(swiftClassFlags() & 1);
return !isActuallySwiftLegacy;
}
void fixupBackwardDeployingStableSwift() {
if (isUnfixedBackwardDeployingStableSwift()) {
// Class really is stable Swift, pretending to be pre-stable.
// Fix its lie.
bits.setIsSwiftStable();
}
}
_objc_swiftMetadataInitializer swiftMetadataInitializer() {
return bits.swiftMetadataInitializer();
}
// Return YES if the class's ivars are managed by ARC,
// or the class is MRC but has ARC-style weak ivars.
//类成员变量的内存管理由ARC管理
//但类是MRC管理
bool hasAutomaticIvars() {
return data()->ro()->flags & (RO_IS_ARC | RO_HAS_WEAK_WITHOUT_ARC);
}
// Return YES if the class's ivars are managed by ARC.
bool isARC() {
return data()->ro()->flags & RO_IS_ARC;
}
bool forbidsAssociatedObjects() {
return (data()->flags & RW_FORBIDS_ASSOCIATED_OBJECTS);
}
#if SUPPORT_NONPOINTER_ISA
// Tracked in non-pointer isas; not tracked otherwise
#else
bool instancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
ASSERT(isFuture() || isRealized());
return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
}
void setInstancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
ASSERT(isFuture() || isRealized());
setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
}
#endif
bool shouldGrowCache() {
return true;
}
void setShouldGrowCache(bool) {
// fixme good or bad for memory use?
}
bool isInitializing() {
return getMeta()->data()->flags & RW_INITIALIZING;
}
void setInitializing() {
ASSERT(!isMetaClass());
ISA()->setInfo(RW_INITIALIZING);
}
bool isInitialized() {
return getMeta()->data()->flags & RW_INITIALIZED;
}
void setInitialized();
bool isLoadable() {
ASSERT(isRealized());
return true; // any class registered for +load is definitely loadable
}
IMP getLoadMethod();
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isRealized() const {
return !isStubClass() && (data()->flags & RW_REALIZED);
}
// Returns true if this is an unrealized future class.
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isFuture() const {
if (isStubClass())
return false;
return data()->flags & RW_FUTURE;
}
bool isMetaClass() const {
ASSERT_THIS_NOT_NULL;
ASSERT(isRealized());
#if FAST_CACHE_META
return cache.getBit(FAST_CACHE_META);
#else
return data()->flags & RW_META;
#endif
}
// Like isMetaClass, but also valid on un-realized classes
bool isMetaClassMaybeUnrealized() {
static_assert(offsetof(class_rw_t, flags) == offsetof(class_ro_t, flags), "flags alias");
static_assert(RO_META == RW_META, "flags alias");
if (isStubClass())
return false;
return data()->flags & RW_META;
}
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClassMaybeUnrealized()) return (Class)this;
else return this->ISA();
}
bool isRootClass() {
return getSuperclass() == nil;
}
bool isRootMetaclass() {
return ISA() == (Class)this;
}
// If this class does not have a name already, we can ask Swift to construct one for us.
const char *installMangledNameForLazilyNamedClass();
// Get the class's mangled name, or NULL if the class has a lazy
// name that hasn't been created yet.
const char *nonlazyMangledName() const {
return bits.safe_ro()->getName();
}
const char *mangledName() {
// fixme can't assert locks here
ASSERT_THIS_NOT_NULL;
const char *result = nonlazyMangledName();
if (!result) {
// This class lazily instantiates its name. Emplace and
// return it.
result = installMangledNameForLazilyNamedClass();
}
return result;
}
const char *demangledName(bool needsLock);
const char *nameForLogging();
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceStart() const {
ASSERT(isRealized());
return data()->ro()->instanceStart;
}
// Class's instance start rounded up to a pointer-size boundary.
// This is used for ARC layout bitmaps.
uint32_t alignedInstanceStart() const {
return word_align(unalignedInstanceStart());
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() const {
ASSERT(isRealized());
return data()->ro()->instanceSize;
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() const {
return word_align(unalignedInstanceSize());
}
inline size_t instanceSize(size_t extraBytes) const {
if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
return cache.fastInstanceSize(extraBytes);
}
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
void setInstanceSize(uint32_t newSize) {
ASSERT(isRealized());
ASSERT(data()->flags & RW_REALIZING);
auto ro = data()->ro();
if (newSize != ro->instanceSize) {
ASSERT(data()->flags & RW_COPIED_RO);
*const_cast<uint32_t *>(&ro->instanceSize) = newSize;
}
cache.setFastInstanceSize(newSize);
}
void chooseClassArrayIndex();
void setClassArrayIndex(unsigned Idx) {
bits.setClassArrayIndex(Idx);
}
unsigned classArrayIndex() {
return bits.classArrayIndex();
}
};
-
superclass
:指向父类的指针; -
cache_t
:方法调用缓存与实例对象内存大小的缓存,其结构体如下:
cache_t
struct cache_t {
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
union {
struct {
explicit_atomic<mask_t> _maybeMask;
#if __LP64__
uint16_t _flags;
#endif
uint16_t _occupied;
};
explicit_atomic<preopt_cache_t *> _originalPreoptCache;
};
void incrementOccupied();
void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
void reallocate(mask_t oldCapacity, mask_t newCapacity, bool freeOld);
void collect_free(bucket_t *oldBuckets, mask_t oldCapacity);
static bucket_t *emptyBuckets();
static bucket_t *allocateBuckets(mask_t newCapacity);
static bucket_t *emptyBucketsForCapacity(mask_t capacity, bool allocate = true);
static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
void bad_cache(id receiver, SEL sel) __attribute__((noreturn, cold));
public:
// The following four fields are public for objcdt's use only.
// objcdt reaches into fields while the process is suspended
// hence doesn't care for locks and pesky little details like this
// and can safely use these.
unsigned capacity() const;
struct bucket_t *buckets() const;
Class cls() const;
#if CONFIG_USE_PREOPT_CACHES
const preopt_cache_t *preopt_cache() const;
#endif
mask_t occupied() const;
void initializeToEmpty();
#if CONFIG_USE_PREOPT_CACHES
bool isConstantOptimizedCache(bool strict = false, uintptr_t empty_addr = (uintptr_t)&_objc_empty_cache) const;
bool shouldFlush(SEL sel, IMP imp) const;
bool isConstantOptimizedCacheWithInlinedSels() const;
Class preoptFallbackClass() const;
void maybeConvertToPreoptimized();
void initializeToEmptyOrPreoptimizedInDisguise();
#else
inline bool isConstantOptimizedCache(bool strict = false, uintptr_t empty_addr = 0) const { return false; }
inline bool shouldFlush(SEL sel, IMP imp) const {
return cache_getImp(cls(), sel) == imp;
}
inline bool isConstantOptimizedCacheWithInlinedSels() const { return false; }
inline void initializeToEmptyOrPreoptimizedInDisguise() { initializeToEmpty(); }
#endif
void insert(SEL sel, IMP imp, id receiver);
void copyCacheNolock(objc_imp_cache_entry *buffer, int len);
void destroy();
void eraseNolock(const char *func);
static void init();
static void collectNolock(bool collectALot);
static size_t bytesForCapacity(uint32_t cap);
#if __LP64__
bool getBit(uint16_t flags) const {
return _flags & flags;
}
void setBit(uint16_t set) {
__c11_atomic_fetch_or((_Atomic(uint16_t) *)&_flags, set, __ATOMIC_RELAXED);
}
void clearBit(uint16_t clear) {
__c11_atomic_fetch_and((_Atomic(uint16_t) *)&_flags, ~clear, __ATOMIC_RELAXED);
}
#endif
#if FAST_CACHE_ALLOC_MASK
bool hasFastInstanceSize(size_t extra) const
{
if (__builtin_constant_p(extra) && extra == 0) {
return _flags & FAST_CACHE_ALLOC_MASK16;
}
return _flags & FAST_CACHE_ALLOC_MASK;
}
size_t fastInstanceSize(size_t extra) const
{
ASSERT(hasFastInstanceSize(extra));
if (__builtin_constant_p(extra) && extra == 0) {
return _flags & FAST_CACHE_ALLOC_MASK16;
} else {
size_t size = _flags & FAST_CACHE_ALLOC_MASK;
// remove the FAST_CACHE_ALLOC_DELTA16 that was added
// by setFastInstanceSize
return align16(size + extra - FAST_CACHE_ALLOC_DELTA16);
}
}
void setFastInstanceSize(size_t newSize)
{
// Set during realization or construction only. No locking needed.
uint16_t newBits = _flags & ~FAST_CACHE_ALLOC_MASK;
uint16_t sizeBits;
// Adding FAST_CACHE_ALLOC_DELTA16 allows for FAST_CACHE_ALLOC_MASK16
// to yield the proper 16byte aligned allocation size with a single mask
sizeBits = word_align(newSize) + FAST_CACHE_ALLOC_DELTA16;
sizeBits &= FAST_CACHE_ALLOC_MASK;
if (newSize <= sizeBits) {
newBits |= sizeBits;
}
_flags = newBits;
}
#else
bool hasFastInstanceSize(size_t extra) const {
return false;
}
size_t fastInstanceSize(size_t extra) const {
abort();
}
void setFastInstanceSize(size_t extra) {
// nothing
}
#endif
};
-
class_data_bits_t
:是一个结构体,此结构体存储了类的数据,其结构如下所示:
class_data_bits_t
struct class_data_bits_t {
friend objc_class;
// Values are the FAST_ flags above.
uintptr_t bits;
private:
bool getBit(uintptr_t bit) const
{
return bits & bit;
}
// Atomically set the bits in `set` and clear the bits in `clear`.
// set and clear must not overlap.
void setAndClearBits(uintptr_t set, uintptr_t clear)
{
ASSERT((set & clear) == 0);
uintptr_t newBits, oldBits = LoadExclusive(&bits);
do {
newBits = (oldBits | set) & ~clear;
} while (slowpath(!StoreReleaseExclusive(&bits, &oldBits, newBits)));
}
void setBits(uintptr_t set) {
__c11_atomic_fetch_or((_Atomic(uintptr_t) *)&bits, set, __ATOMIC_RELAXED);
}
void clearBits(uintptr_t clear) {
__c11_atomic_fetch_and((_Atomic(uintptr_t) *)&bits, ~clear, __ATOMIC_RELAXED);
}
public:
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
void setData(class_rw_t *newData)
{
ASSERT(!data() || (newData->flags & (RW_REALIZING | RW_FUTURE)));
// Set during realization or construction only. No locking needed.
// Use a store-release fence because there may be concurrent
// readers of data and data's contents.
uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
atomic_thread_fence(memory_order_release);
bits = newBits;
}
// Get the class's ro data, even in the presence of concurrent realization.
// fixme this isn't really safe without a compiler barrier at least
// and probably a memory barrier when realizeClass changes the data field
const class_ro_t *safe_ro() const {
class_rw_t *maybe_rw = data();
if (maybe_rw->flags & RW_REALIZED) {
// maybe_rw is rw
return maybe_rw->ro();
} else {
// maybe_rw is actually ro
return (class_ro_t *)maybe_rw;
}
}
#if SUPPORT_INDEXED_ISA
void setClassArrayIndex(unsigned Idx) {
// 0 is unused as then we can rely on zero-initialisation from calloc.
ASSERT(Idx > 0);
data()->index = Idx;
}
#else
void setClassArrayIndex(__unused unsigned Idx) {
}
#endif
unsigned classArrayIndex() {
#if SUPPORT_INDEXED_ISA
return data()->index;
#else
return 0;
#endif
}
bool isAnySwift() {
return isSwiftStable() || isSwiftLegacy();
}
bool isSwiftStable() {
return getBit(FAST_IS_SWIFT_STABLE);
}
void setIsSwiftStable() {
setAndClearBits(FAST_IS_SWIFT_STABLE, FAST_IS_SWIFT_LEGACY);
}
bool isSwiftLegacy() {
return getBit(FAST_IS_SWIFT_LEGACY);
}
void setIsSwiftLegacy() {
setAndClearBits(FAST_IS_SWIFT_LEGACY, FAST_IS_SWIFT_STABLE);
}
// fixme remove this once the Swift runtime uses the stable bits
bool isSwiftStable_ButAllowLegacyForNow() {
return isAnySwift();
}
_objc_swiftMetadataInitializer swiftMetadataInitializer() {
// This function is called on un-realized classes without
// holding any locks.
// Beware of races with other realizers.
return safe_ro()->swiftMetadataInitializer();
}
};
-
bits
:与掩码FAST_DATA_MASK做位与运算
可以得到class_rw_t
结构体; -
class_rw_t *data()
:获取类class的相关数据,返回是一个class_rw_t
类型的结构体,表明类class的数据信息都存储在class_rw_t
结构体中;
class_rw_t结构体
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint16_t witness;
#if SUPPORT_INDEXED_ISA
uint16_t index;
#endif
explicit_atomic<uintptr_t> ro_or_rw_ext;
Class firstSubclass;
Class nextSiblingClass;
private:
using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t, class_rw_ext_t, PTRAUTH_STR("class_ro_t"), PTRAUTH_STR("class_rw_ext_t")>;
//联合 ro__rwe
const ro_or_rw_ext_t get_ro_or_rwe() const {
return ro_or_rw_ext_t{ro_or_rw_ext};
}
void set_ro_or_rwe(const class_ro_t *ro) {
ro_or_rw_ext_t{ro, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_relaxed);
}
void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {
// the release barrier is so that the class_rw_ext_t::ro initialization
// is visible to lockless readers
rwe->ro = ro;
ro_or_rw_ext_t{rwe, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_release);
}
class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);
public:
void setFlags(uint32_t set)
{
__c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED);
}
void clearFlags(uint32_t clear)
{
__c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED);
}
// set and clear must not overlap
void changeFlags(uint32_t set, uint32_t clear)
{
ASSERT((set & clear) == 0);
uint32_t oldf, newf;
do {
oldf = flags;
newf = (oldf | set) & ~clear;
} while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
}
class_rw_ext_t *ext() const {
return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext);
}
class_rw_ext_t *extAllocIfNeeded() {
auto v = get_ro_or_rwe();
if (fastpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext);
} else {
return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));
}
}
class_rw_ext_t *deepCopy(const class_ro_t *ro) {
return extAlloc(ro, true);
}
const class_ro_t *ro() const {
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
}
return v.get<const class_ro_t *>(&ro_or_rw_ext);
}
void set_ro(const class_ro_t *ro) {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro = ro;
} else {
set_ro_or_rwe(ro);
}
}
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
} else {
return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
}
}
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
} else {
return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
}
}
const protocol_array_t protocols() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
}
}
};
-
uint32_t flags
:可以理解成描述类class的状态标识,其与不同的状态掩码值做位与运算可以得到类class的状态; -
ro_or_rw_ext_t
:是调用C++函数,将class_ro_t
与class_rw_ext_t
联合在一起,形成一个新的结构体;
class_rw_ext_t
struct class_rw_ext_t {
DECLARE_AUTHED_PTR_TEMPLATE(class_ro_t)
class_ro_t_authed_ptr<const class_ro_t> ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
char *demangledName;
uint32_t version;
};
class_ro_t
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
union {
const uint8_t * ivarLayout;
Class nonMetaclass;
};
explicit_atomic<const char *> name;
// With ptrauth, this is signed if it points to a small list, but
// may be unsigned if it points to a big list.
void *baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
// This field exists only when RO_HAS_SWIFT_INITIALIZER is set.
_objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];
_objc_swiftMetadataInitializer swiftMetadataInitializer() const {
if (flags & RO_HAS_SWIFT_INITIALIZER) {
return _swiftMetadataInitializer_NEVER_USE[0];
} else {
return nil;
}
}
const char *getName() const {
return name.load(std::memory_order_acquire);
}
static const uint16_t methodListPointerDiscriminator = 0xC310;
#if 0 // FIXME: enable this when we get a non-empty definition of __ptrauth_objc_method_list_pointer from ptrauth.h.
static_assert(std::is_same<
void * __ptrauth_objc_method_list_pointer *,
void * __ptrauth(ptrauth_key_method_list_pointer, 1, methodListPointerDiscriminator) *>::value,
"Method list pointer signing discriminator must match ptrauth.h");
#endif
method_list_t *baseMethods() const {
#if __has_feature(ptrauth_calls)
method_list_t *ptr = ptrauth_strip((method_list_t *)baseMethodList, ptrauth_key_method_list_pointer);
if (ptr == nullptr)
return nullptr;
// Don't auth if the class_ro and the method list are both in the shared cache.
// This is secure since they'll be read-only, and this allows the shared cache
// to cut down on the number of signed pointers it has.
bool roInSharedCache = objc::inSharedCache((uintptr_t)this);
bool listInSharedCache = objc::inSharedCache((uintptr_t)ptr);
if (roInSharedCache && listInSharedCache)
return ptr;
// Auth all other small lists.
if (ptr->isSmallList())
ptr = ptrauth_auth_data((method_list_t *)baseMethodList,
ptrauth_key_method_list_pointer,
ptrauth_blend_discriminator(&baseMethodList,
methodListPointerDiscriminator));
return ptr;
#else
return (method_list_t *)baseMethodList;
#endif
}
uintptr_t baseMethodListPtrauthData() const {
return ptrauth_blend_discriminator(&baseMethodList,
methodListPointerDiscriminator);
}
class_ro_t *duplicate() const {
bool hasSwiftInitializer = flags & RO_HAS_SWIFT_INITIALIZER;
size_t size = sizeof(*this);
if (hasSwiftInitializer)
size += sizeof(_swiftMetadataInitializer_NEVER_USE[0]);
class_ro_t *ro = (class_ro_t *)memdup(this, size);
if (hasSwiftInitializer)
ro->_swiftMetadataInitializer_NEVER_USE[0] = this->_swiftMetadataInitializer_NEVER_USE[0];
#if __has_feature(ptrauth_calls)
// Re-sign the method list pointer if it was signed.
// NOTE: It is possible for a signed pointer to have a signature
// that is all zeroes. This is indistinguishable from a raw pointer.
// This code will treat such a pointer as signed and re-sign it. A
// false positive is safe: method list pointers are either authed or
// stripped, so if baseMethods() doesn't expect it to be signed, it
// will ignore the signature.
void *strippedBaseMethodList = ptrauth_strip(baseMethodList, ptrauth_key_method_list_pointer);
void *signedBaseMethodList = ptrauth_sign_unauthenticated(strippedBaseMethodList,
ptrauth_key_method_list_pointer,
baseMethodListPtrauthData());
if (baseMethodList == signedBaseMethodList) {
ro->baseMethodList = ptrauth_auth_and_resign(baseMethodList,
ptrauth_key_method_list_pointer,
baseMethodListPtrauthData(),
ptrauth_key_method_list_pointer,
ro->baseMethodListPtrauthData());
} else {
// Special case: a class_ro_t in the shared cache pointing to a
// method list in the shared cache will not have a signed pointer,
// but the duplicate will be expected to have a signed pointer since
// it's not in the shared cache. Detect that and sign it.
bool roInSharedCache = objc::inSharedCache((uintptr_t)this);
bool listInSharedCache = objc::inSharedCache((uintptr_t)strippedBaseMethodList);
if (roInSharedCache && listInSharedCache)
ro->baseMethodList = ptrauth_sign_unauthenticated(strippedBaseMethodList,
ptrauth_key_method_list_pointer,
ro->baseMethodListPtrauthData());
}
#endif
return ro;
}
Class getNonMetaclass() const {
ASSERT(flags & RO_META);
return nonMetaclass;
}
const uint8_t *getIvarLayout() const {
if (flags & RO_META)
return nullptr;
return ivarLayout;
}
};
-
flags
:标识; -
instanceSize
:实例的内存大小; -
baseMethodList
:方法列表 -
baseProtocols
:协议列表 -
baseProperties
:属性列表 -
ivars
:成员变量列表
总结:
-
OC中的任意对象id,都是以objc_object为模板创建的,所以实例对象,类对象,元类对象都会有isa指针;
-
OC中的class类对象,都是以objc_class为模板创建,而objc_class继承自objc_object,所以也会有isa指针;
-
class_ro_t
是其内部的成员; -
Class
的本质就是objc_class结构体
typedef struct objc_class *Class;
-
id
的本质就是objc_object结构体
typedef struct objc_object *id;
上述结构体之间的关系图如下:
object_class.png- 从上述的结构图中可以看出,对象包括实例对象,类对象,元类对象,只要是继承自objc_object对象都有isa指针成员变量;
- 类对象才有superClass指针,元类对象也存在superClass指针,只有是继承自objc_class的对象都有superClass指针,而实例对象是没有superClass指针的,表明实例对象之间是没有继承关系的,继承关系只表现在类对象与元类对象之间;
断言Assert
int main(int argc, const char * argv[]) {
@autoreleasepool {
BOOL isTaggedPointer = NO;
assert(isTaggedPointer);
NSLog(@"success");
}
return 0;
}
-
assert(isTaggedPointer)
:会出现崩溃,因为参数isTaggedPointer = NO; - assert(参数),只有参数为真时,程序才会正常往下执行,否则会出现崩溃。