inlinevoidobjc_object::initIsa(Class cls,bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor){ ASSERT(!isTaggedPointer()); isa_tnewisa(0);if (!nonpointer) {newisa.setClass(cls,this); } else {ASSERT(!DisableNonpointerIsa);ASSERT(!cls->instancesRequireRawIsa());#ifSUPPORT_INDEXED_ISAASSERT(cls->classArrayIndex() >0);newisa.bits = ISA_INDEX_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUEnewisa.has_cxx_dtor = hasCxxDtor;newisa.indexcls = (uintptr_t)cls->classArrayIndex();#elsenewisa.bits = ISA_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUE# ifISA_HAS_CXX_DTOR_BITnewisa.has_cxx_dtor = hasCxxDtor;# endifnewisa.setClass(cls,this);#endifnewisa.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;}
2.2 isa的本质 isa_t
从源码中我们看到isa的类型为isa_t,我们找到isa_t的源码:
unionisa_t { // 构造方法isa_t() { }isa_t(uintptr_t value) :bits(value) { }uintptr_t bits;private: // Accessing the class requires custom ptrauth operations, so // force clients to go through setClass/getClass by making this // private. Class cls;public:#ifdefined(ISA_BITFIELD)struct { ISA_BITFIELD; // defined in isa.h };boolisDeallocating() {return extra_rc ==0&& has_sidetable_rc ==0; }voidsetDeallocating() { extra_rc =0; has_sidetable_rc =0; }#endifvoidsetClass(Class cls,objc_object*obj);ClassgetClass(bool authenticated);ClassgetDecodedClass(bool authenticated);};
inline Classisa_t::getClass(MAYBE_UNUSED_AUTHENTICATED_PARAM bool authenticated) {#ifSUPPORT_INDEXED_ISAreturn cls;#elseuintptr_t clsbits = bits;# if __has_feature(ptrauth_calls)# ifISA_SIGNING_AUTH_MODE==ISA_SIGNING_AUTH // Most callers aren't security critical, so skip the // authentication unless they ask for it. Message sending and // cache filling are protected by the auth code in msgSend.if (authenticated) { // Mask off all bits besides the class pointer and signature. clsbits &= ISA_MASK;if (clsbits ==0)return Nil; clsbits = (uintptr_t)ptrauth_auth_data((void *)clsbits, ISA_SIGNING_KEY, ptrauth_blend_discriminator(this, ISA_SIGNING_DISCRIMINATOR));
} else { // If not authenticating, strip using the precomputed class mask. clsbits &= objc_debug_isa_class_mask; }# else // If not authenticating, strip using the precomputed class mask. clsbits &= objc_debug_isa_class_mask;# endif# else clsbits &= ISA_MASK;# endifreturn (Class)clsbits;#endif}
inlinevoidobjc_object::initIsa(Class cls,bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor){ ASSERT(!isTaggedPointer()); isa_tnewisa(0);if (!nonpointer) { // 如果是纯isa就直接setClassnewisa.setClass(cls,this); } else {ASSERT(!DisableNonpointerIsa);ASSERT(!cls->instancesRequireRawIsa());#ifSUPPORT_INDEXED_ISAASSERT(cls->classArrayIndex() >0);newisa.bits = ISA_INDEX_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUEnewisa.has_cxx_dtor = hasCxxDtor;newisa.indexcls = (uintptr_t)cls->classArrayIndex();#elsenewisa.bits = ISA_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUE# ifISA_HAS_CXX_DTOR_BITnewisa.has_cxx_dtor = hasCxxDtor;# endifnewisa.setClass(cls,this);#endifnewisa.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;}
3.1 class绑定流程图
3.2 中间有个判断 Nonpointer isa
下面我们具体研究下
四、Nonpointer isa
在上面我们有多次看到Nonpointer isa出现。现在我们深入的研究一下
4.1 isa_t
在上面我们知道isa是一个联合体,而联合体成员是互斥的。
这个就是Nonpointer isa区别于纯isa的核心!
4.2 isa_t::setClass
这里是设置Class的核心实现
// Set the class field in an isa. Takes both the class to set and// a pointer to the object where the isa will ultimately be used.// This is necessary to get the pointer signing right.//// Note: this method does not support setting an indexed isa. When// indexed isas are in use, it can only be used to set the class of a// raw isa.inlinevoidisa_t::setClass(Class newCls, UNUSED_WITHOUT_PTRAUTH objc_object *obj){ // Match the conditional in isa.h.#if __has_feature(ptrauth_calls) ||TARGET_OS_SIMULATOR# ifISA_SIGNING_SIGN_MODE==ISA_SIGNING_SIGN_NONE // No signing, just use the raw pointer.uintptr_t signedCls = (uintptr_t)newCls;# elif ISA_SIGNING_SIGN_MODE == ISA_SIGNING_SIGN_ONLY_SWIFT // We're only signing Swift classes. Non-Swift classes just use // the raw pointeruintptr_t signedCls = (uintptr_t)newCls;if (newCls->isSwiftStable()) signedCls = (uintptr_t)ptrauth_sign_unauthenticated((void *)newCls, ISA_SIGNING_KEY, ptrauth_blend_discriminator(obj, ISA_SIGNING_DISCRIMINATOR));
# elif ISA_SIGNING_SIGN_MODE == ISA_SIGNING_SIGN_ALL // We're signing everything uintptr_t signedCls = (uintptr_t)ptrauth_sign_unauthenticated((void *)newCls, ISA_SIGNING_KEY, ptrauth_blend_discriminator(obj, ISA_SIGNING_DISCRIMINATOR));
# else# errorUnknown isa signing mode.# endif shiftcls_and_sig = signedCls >>3;#elif SUPPORT_INDEXED_ISA // Indexed isa only uses this method to set a raw pointer class. // Setting an indexed class is handled separately. cls = newCls;#else // Nonpointer isa, no ptrauth shiftcls = (uintptr_t)newCls >>3;#endif}