《OC底层系列三》-对象和类的关联

2020-05-10  本文已影响0人  002and001

前言

我们都知道对象由类实例化而来,在上一篇《OC底层系列二》-对象中,我们知道对象是一个objc_object类型的结构体类是一个objc_class类型的结构体,今天我们从底层来探究对象和类是如何建立关联

目录

image.png

0、简介

1、对象和类的定义

typedef struct objc_class *Class; // 类的定义
typedef struct objc_object *id;  // 对象的定义

1.1、objc_object

// objc-private.h

// objc_object 的实现
struct objc_object {
private:
    isa_t isa;
以下是一些函数,省略
...
}

1.2、objc_class

// objc-runtime-new.h

struct objc_class : objc_object {
    // 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_rw_t *data() { 
        return bits.data();
    } 
// objc_class的部分方法代码省略不贴出来
}

2、isa

// objc-private.h

// isa_t的定义,一个联合体,值为cls或者bits
union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

2.1、isa的初始化

// objc_private.h

struct objc_object {
private:
    isa_t isa;

public:  
···
private:
    void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
···
}
// objc-object.h

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    assert(!isTaggedPointer()); 
    
    if (!nonpointer) {
// 2.1.1
        isa.cls = cls;
    } else {
// 2.1.2
        assert(!DisableNonpointerIsa);
        assert(!cls->instancesRequireRawIsa());

        isa_t newisa(0);

#if SUPPORT_INDEXED_ISA
// 2.1.3
        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
// 2.1.4
        newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif

        // 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;
    }
}
// objc-config.h

// Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa 
// field as an index into a class table.
// Note, keep this in sync with any .s files which also define it.
// Be sure to edit objc-abi.h as well.
#if __ARM_ARCH_7K__ >= 2  ||  (__arm64__ && !__LP64__)
#   define SUPPORT_INDEXED_ISA 1
#else
#   define SUPPORT_INDEXED_ISA 0
#endif
// ARM.cpp

// Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU
// happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__.
if (getTriple().isWatchABI())
  Builder.defineMacro("__ARM_ARCH_7K__", "2");
// 2.1.4
 newisa.bits = ISA_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.shiftcls = (uintptr_t)cls >> 3;

2.2、shiftcls

shiftcls的值是isa中cls的值右移三位得到,shiftcls存储类指针的值。根据shiftcls的宏定义,在 x86_64 架构有 44位 用来存储类指针,arm64 架构中有 33位 。

#import <Foundation/Foundation.h>
// Animal继承NSObject,没有添加任何成员
#import "Animal.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Animal *animal = [Animal alloc];
        NSLog(@"Hello, World!");
    }
    return 0;
}
格式化二进制如下:
// [animal class]
$0 = 0b 0000 0000 0000 0000 00   00 0000 0000 0001 0000 0000 0000 0000 0010 0000 1111 0   000
// isa
$2 = 0b 0000 0000 0001 1101 10   00 0000 0000 0001 0000 0000 0000 0000 0010 0000 1111 0   001

3、[object class]方法分析

\\ objc-object.h
inline Class 
objc_object::ISA() 
{
    ASSERT(!isTaggedPointer()); 
#if SUPPORT_INDEXED_ISA
// 3.1
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
// 3.2
    return (Class)(isa.bits & ISA_MASK);
#endif
}
// isa.h

define ISA_MASK        0x00007ffffffffff8ULL

4、通过LLDB验证对象和类如何关联

5、总结

6、TODO

上一篇 下一篇

猜你喜欢

热点阅读