Previous review:

Underlying principles of iOS: the nature of OC objects

OC: struct (struct)/ bit field/union (union)

Having seen what objects look like in C++ through clang, let’s look at the nature of objects in combination with source code.

Isa quest

First look at the objc_class definition in the source code and find nothing useful. Objc_class simply contains a Class isa, and Class is just a pointer alias to objc_class, a nesting doll. Of course, this is inside OBJC, but we generally use __OBJC2__. Find our definition of objc_class. Objc_class abridged inheritance and objc_Object. Because the code is too long, here is a screenshot. This is just a pointer. I don’t know what’s in the pointer.

typedef struct objc_class *Class; struct objc_class { Class _Nonnull isa OBJC_ISA_AVAILABILITY; #if ! __OBJC2__ Class _Nullable super_class OBJC2_UNAVAILABLE; const char * _Nonnull name OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; #endif } OBJC2_UNAVAILABLE;Copy the code

Then you can only review the source code objectallocBecause it appears in the processinitInstanceIsaWe just have to follow this. Find the key stepsobjc_object::initIsa.isa_tIt should be oursisa.

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; // 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; }Copy the code

Isa_t is defined like this.

union isa_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:
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };

    bool isDeallocating() {
        return extra_rc == 0 && has_sidetable_rc == 0;
    }
    void setDeallocating() {
        extra_rc = 0;
        has_sidetable_rc = 0;
    }
#endif
Copy the code

Then in the macro definition ISA_BITFIELD, go into the macro definition and see that Apple tells us how to put isa, in the ios emulator and the real machine is different, macOS is different.

Isa structure

nonpointer

0: pure ISA pointer. 1: contains not only the object address, but also class information, object reference count, and weak references.

has_assoc

Has_assoc has any associated objects set. If not, the release will be faster

has_cxx_dtor

Has_cxx_dtor does have a C++ destructor (.cxx_destruct), if not, it will be released faster

shiftcls

Shiftcls stores the memory addresses of Class and meta-class objects. In the case of nonpointer=1, 33 bits are used to store Class Pointers in arm64.

magic

Magic is used to tell if an object has not been initialized during debugging

weakly_referenced

Weakly_referenced Whether a weak reference has been pointed to, if not, it will be released faster. Weak reference table.

deallocating

The DealLocating object is being released

has_sidetable_rc

Has_sidetable_rc Is the reference counter too large to be stored in ISA if it is 1, then the reference count is stored in an attribute of a class called SideTable

extra_rc

The value stored in extra_rc is the reference counter minus 1. If the reference count is 10 and the reference count is 9, has_sidetable_rc is used if the reference count is greater than 10.

Isa analysis

  • isa_tIt’s a union with member variablesbits andcls, there is also an anonymous struct type, which containsISA_BITFIELD.thisISA_BITFIELDThe use of bitfields is perfect for storing Pointers to classes and related information, telling us what is stored in isa!
  • isaDivided intononpointerThe type andThe nonpointeR.The nonpointerThe type is just a pure pointer,nonpointerIt also contains additional information about the class.
  • isaIs the union + bitfield way to store information. Using this method can save a lot of memory. Everything is an object, so long as it is an objectisaPointers, lots of themisaIt takes up a lot of memory, commonwealth common a piece of memory to save part of memory, and bit domain is in the memory saving basis to store more information, fully this8 bytesUse the full, this can be seen very clearlyisaData stored in each bit.

Isa Practice Research

throughinitIsaTake a look atisaThe initial process of.

1. Inobjc_object::initIsaHit the break point and waitLQPeopleComing to me. The first is throughisa_tThe structure of the structure turned over to construct aisa_tThe consortium

2. ThenbitsThe assignmentISA_MAGIC_VALUE.ISA_MAGIC_VALUEFor the macro definition0x001f800000000001ULL , can be seen after viewing using binarynonpointerfor1.magicfor59.

1. 3. Smart refrigeratorsetClass, this willclsThat isLQpeopleThe incoming.

4. To entersetClassHere, giveshiftclsIt’s assigned. The value is zeroclsMoves to the right3position

Through 5.lldbLook at thenewisa.

6. Finally, giveextra_rc(reference counter) is assigned.extra_rcOccupy 8 bits.

7. At this point, initIsa is finished, and then go to the code to verify

Verify ISA in the code

Here we seepThe first address of the object is what we just storedisa!

Isa pushes back the class pointer

1. Direct bit complement

Find Shiftisa and look at it in binary. Add 17 zeros in front of it, not 3 after it, because this is macOS environment, so it works like this. This method is too stupid.

2. Bit operations

We use bitoperations to squeeze out the lower three bits and the higher 17 bits, and we’re left with our class pointer

3. And upper mask

With the ISA_MASK in one step!