iOS Runtime - isa pointer

Objective-C is a relatively dynamic programming language, which is very different from languages ​​such as C and C++. The process of ordinary languages ​​is roughly divided into: writing code -> compiling and linking -> running.

How to achieve the dynamic nature of OC?

The dynamics of Objective-C are supported by the Runtime API. The interfaces provided by the Runtime API are basically in C language. The source code is written in C\C++\assembly language. Today, let’s take a look at the essence and implementation principles of Runtime.

The essence of isa

Before learning Runtime, you first need to have a certain understanding of the nature of isa, so that it will be easier to understand after learning Runtime.
In this article, a peek into the nature of iOS OC objects (1) mentioned that each OC object contains an isa pointer. Before __arm64__, isa was just a pointer, saving the memory address of an object or class object. In __arm64_ After the _architecture, Apple optimized isa and turned it into a union structure, while using bit fields to store more information.

We know that the isa pointer of the OC object does not directly point to the address of the class object or metaclass object, but requires &ISA_MASK to obtain the address of the class object or metaclass object through bit operations. Today, let’s explore why &ISA_MASK is needed to obtain the address of a class object or metaclass object, and the benefits of this.

First find the isa pointer in the source code and take a look at the nature of the isa pointer.

// objc_object内部分代码
struct objc_object {
private:
    isa_t isa;
}

The isa pointer is actually a union of type isa_t. Go inside isa_t to view its structure.

// 精简过的isa_t共用体
union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;

#if SUPPORT_PACKED_ISA
# if __arm64__      
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
    struct {
        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 deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19;
    #       define RC_ONE   (1ULL<<45)
    #       define RC_HALF  (1ULL<<18)
    };

# elif __x86_64__     
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
    struct {
        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 deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 8;
#       define RC_ONE   (1ULL<<56)
#       define RC_HALF  (1ULL<<7)
    };

# else
#   error unknown architecture for packed isa
# endif
#endif

In the above source code, isa_t is a union type, and union represents a union. You can see that there is a structure in the union, and some variables are defined inside the structure. The value behind the variable represents how many binary bits the variable occupies, which is bit field technology.

Union: When programming certain algorithms in C language, several different types of variables need to be stored in the same memory unit. That is, using coverage technology, several variables cover each other. This structure in which several different variables jointly occupy a section of memory is called a "union" type structure in the C language, or a union for short.


 

Guess you like

Origin blog.csdn.net/yezuiqingxin/article/details/119572019