Introduction: In the course of exploring the principle of 001-OC object – Alloc, the basic process of alloc is generally described. The following code in the _class_createInstanceFromZone method gives a brief introduction to object association.
if (! zone && fast) { obj->initInstanceIsa(cls, hasCxxDtor); } else { obj->initIsa(cls); }Copy the code
Therefore, this article will explore this mysterious ISA in detail. InitInstanceIsa (CLS,hasCxxDtor); initInstanceIsa(CLS,hasCxxDtor)
ASSERT(! cls->instancesRequireRawIsa()); ASSERT(hasCxxDtor == cls->hasCxxDtor());Copy the code
InstancesRequireRawIsa () contains cache.getBit(FAST_CACHE_REQUIRES_RAW_ISA); . Where “FAST_CACHE_REQUIRES_RAW_ISA” refers to whether the 13th bit of the uint16_t _flags in the cache_T of the class is 1, which indicates whether the class object (non-instance object) needs the original ISA.
Cache.getbit (FAST_CACHE_HAS_CXX_DTOR); . Where FAST_CACHE_HAS_CXX_DTOR refers to whether the 2nd bit of the uint16_t _flags in the cache_t class is 1, which indicates whether the current class or its parent class has c++ destructor implementation.
Next comes initIsa(CLS, true, hasCxxDtor); The internal source code is as follows:
inline void objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor) { 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; newisa.has_cxx_dtor = hasCxxDtor; newisa.indexcls = (uintptr_t)cls->classArrayIndex(); #else newisa.bits = ISA_MAGIC_VALUE; # if ISA_HAS_CXX_DTOR_BIT newisa.has_cxx_dtor = hasCxxDtor; # endif newisa.setClass(cls, this); #endif newisa.extra_rc = 1; } isa = newisa; }Copy the code
InitInstanceIsa: int int int int int int int int int int int int int int int int int int int int int int 2, by the obj – > initIsa (CLS); Nonpointer in initIsa passes the value false, following the internal if logic, only for newisa’s class. 3. In the initIsa method, ASSERT(! isTaggedPointer()); Whether it is TaggedPointer. If TaggedPointer is TaggedPointer, the subsequent logic cannot be continued, that is, no ISA.
The internal members of the union are mutually exclusive, that is, the size of the union is determined by the size of the largest internal member. Struct is “large and accommodating”, and the memory size can be explored by referring to the principle of 002-OC object – internal preservation and alignment of structure
Union isa_t {isa_t() {} uintptr_t () : bits(value) {} private: Class cls; public: #if defined(ISA_BITFIELD) struct { ISA_BITFIELD; // This macro is isa internal bitfield allocation, source code is below}; bool isDeallocating() { return extra_rc == 0 && has_sidetable_rc == 0; } void setDeallocating() { extra_rc = 0; has_sidetable_rc = 0; } #endif void setClass(Class cls, objc_object *obj); Class getClass(bool authenticated); Class getDecodedClass(bool authenticated); };Copy the code
Wherein, ISA_BITFIELD is the allocation of the internal bit field of ISA: (:1, :44, etc., indicate that the member occupies 1 and 44 bits respectively)
# if __arm64__
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t unused : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 19
# elif __x86_64__
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t unused : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 8
Copy the code
–nonpointer
: Enable or notNONPOINTER isa
Pointer optimization; –has_assoc
: Whether the object contains an associated reference –has_cxx_dtor
: whether the object contains a destructor for C++ or Objc –shiftcls
: Pointer to class (emphasis) (arm64:33 bits, x86_64:44 bits) –magic
: Indicates whether the object is initialized (arm64:0x16, x86_64:0x3b) –weakly_referenced
: Whether the object is weakly referenced –deallocating
: Whether the object is performing a destructor (freeing memory) –has_sidetable_rc
Sidetable is used to handle reference counting, (the extra_rc size affects this variable)extra_rc
The binary distribution of ISA is shown below:
####TaggedPointer In early 64-bit architectures, basic data types were stored, which were encapsulated as NSnumbers, which allocated 8 bytes of memory in the heap, and 4 bytes in 32-bit architectures. Maintain reference counts and manage lifetimes. Cause the loss of operating efficiency. It wastes a lot of space. Therefore, TaggedPointer is introduced. When the assertion is TaggedPointer, the value of the object pointer is not the address, but the real value, which directly optimizes memory and improves retrieval speed. #### Nonpointer inside the ISA_BITFIELD, you can see that nonpointer has 1 bit indicating whether pointer optimization is enabled on isa Pointers (0: pure ISA Pointers, 1: More than just class object addresses, ISA contains class information, object reference counts, and so on. Apply judgment, as described above.
The use of ISA and the direction of ISA will be explored in the next article. Each class has an ISA. The importance of isa exploration is self-evident. We explored the internal structure of ISA through the alloc process and filled a hole in the Alloc process in article 001. I’m so tired. Bye.