From 37964b8e63e294772c34aef7ead815a96e435553 Mon Sep 17 00:00:00 2001 From: Owenli Date: Wed, 12 Sep 2018 13:38:11 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85isa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...1.\347\254\254\344\270\200\351\242\230.md" | 7 +++ ...0.\347\254\254\345\215\201\351\242\230.md" | 54 +++++++++++++++++++ ...54\345\215\201\344\270\211\351\242\230.md" | 22 +++++--- ...54\345\215\201\345\233\233\351\242\230.md" | 2 + ...2.\347\254\254\344\272\214\351\242\230.md" | 21 ++++++-- ...14\345\215\201\344\270\200\351\242\230.md" | 45 ++++++++++++++++ 6 files changed, 141 insertions(+), 10 deletions(-) diff --git "a/Runtime/1.\347\254\254\344\270\200\351\242\230.md" "b/Runtime/1.\347\254\254\344\270\200\351\242\230.md" index 4d8377b..c5af494 100644 --- "a/Runtime/1.\347\254\254\344\270\200\351\242\230.md" +++ "b/Runtime/1.\347\254\254\344\270\200\351\242\230.md" @@ -2,5 +2,12 @@ 具体可以参看 `Runtime` 源代码,在文件 `objc-private.h` 的第 `127-232` 行。 +``` +struct objc_object { + isa_t isa; + //... +} +``` + 本质上 `objc_object` 的私有属性只有一个 `isa` 指针。指向 `类对象` 的内存地址。 diff --git "a/Runtime/10.\347\254\254\345\215\201\351\242\230.md" "b/Runtime/10.\347\254\254\345\215\201\351\242\230.md" index 3b4808c..fc772fe 100644 --- "a/Runtime/10.\347\254\254\345\215\201\351\242\230.md" +++ "b/Runtime/10.\347\254\254\345\215\201\351\242\230.md" @@ -12,3 +12,57 @@ - `NON_POINTER_ISA`,除了内存地址,还存有一些其他信息 +# isa源码分析 + +在Runtime源码查看isa_t是共用体。简化结构如下: + +```objc +union isa_t +{ + Class cls; + uintptr_t bits; + # if __arm64__ // arm64架构 +# define ISA_MASK 0x0000000ffffffff8ULL //用来取出33位内存地址使用(&)操作 +# define ISA_MAGIC_MASK 0x000003f000000001ULL +# define ISA_MAGIC_VALUE 0x000001a000000001ULL + struct { + uintptr_t nonpointer : 1; //0:代表普通指针,1:表示优化过的,可以存储更多信息。 + uintptr_t has_assoc : 1; //是否设置过关联对象。如果没设置过,释放会更快 + uintptr_t has_cxx_dtor : 1; //是否有C++的析构函数 + 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; //引用计数器是否过大无法存储在ISA中。如果为1,那么引用计数会存储在一个叫做SideTable的类的属性中 + uintptr_t extra_rc : 19; //里面存储的值是引用计数器减1 + +# define RC_ONE (1ULL<<45) +# define RC_HALF (1ULL<<18) + }; + +# elif __x86_64__ // arm86架构,模拟器是arm86 +# 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 + +} +``` + +> 注意:什么是位域? \ No newline at end of file diff --git "a/Runtime/13.\347\254\254\345\215\201\344\270\211\351\242\230.md" "b/Runtime/13.\347\254\254\345\215\201\344\270\211\351\242\230.md" index 1cb01e0..2a6484d 100644 --- "a/Runtime/13.\347\254\254\345\215\201\344\270\211\351\242\230.md" +++ "b/Runtime/13.\347\254\254\345\215\201\344\270\211\351\242\230.md" @@ -5,18 +5,28 @@ `ObjC` 类中的属性、方法还有遵循的协议等信息都保存在 `class_rw_t` 中: ```objc -struct class_rw_t { +// 可读可写 +struct class_rw_t { + // Be warned that Symbolication knows the layout of this structure. uint32_t flags; uint32_t version; - const class_ro_t *ro; + const class_ro_t *ro; // 指向只读的结构体,存放类初始信息 - method_array_t methods; - property_array_t properties; - protocol_array_t protocols; + /* + 这三个都是二位数组,是可读可写的,包含了类的初始内容、分类的内容。 + methods中,存储 method_list_t ----> method_t + 二维数组,method_list_t --> method_t + 这三个二位数组中的数据有一部分是从class_ro_t中合并过来的。 + */ + method_array_t methods; // 方法列表(类对象存放对象方法,元类对象存放类方法) + property_array_t properties; // 属性列表 + protocol_array_t protocols; //协议列表 Class firstSubclass; Class nextSiblingClass; -}; + + //... + } ``` diff --git "a/Runtime/14.\347\254\254\345\215\201\345\233\233\351\242\230.md" "b/Runtime/14.\347\254\254\345\215\201\345\233\233\351\242\230.md" index 7083882..c295091 100644 --- "a/Runtime/14.\347\254\254\345\215\201\345\233\233\351\242\230.md" +++ "b/Runtime/14.\347\254\254\345\215\201\345\233\233\351\242\230.md" @@ -22,4 +22,6 @@ struct class_ro_t { }; ``` +`baseMethodList`,`baseProtocols`,`ivars`,`baseProperties`三个都是以为数组。 + diff --git "a/Runtime/2.\347\254\254\344\272\214\351\242\230.md" "b/Runtime/2.\347\254\254\344\272\214\351\242\230.md" index bb41eeb..5f85baf 100644 --- "a/Runtime/2.\347\254\254\344\272\214\351\242\230.md" +++ "b/Runtime/2.\347\254\254\344\272\214\351\242\230.md" @@ -4,11 +4,24 @@ > 类对象就是 `objc_class`。 -它的结构相对丰富一些。 +``` +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 用于获取地址 -- `superClass`:指向父类 -- `Cache`:方法的缓存列表 -- `data`:顾名思义,就是数据。是一个被封装好的 `class_rw_t` 。 + class_rw_t *data() { + return bits.data(); // &FAST_DATA_MASK 获取地址值 + } +``` + +它的结构相对丰富一些。继承自`objc_object`结构体,所以包含`isa`指针 + +- `isa`:指向元类 +- `superClass`: 指向父类 +- `Cache`: 方法的缓存列表 +- `data`: 顾名思义,就是数据。是一个被封装好的 `class_rw_t` 。 diff --git "a/Runtime/21.\347\254\254\344\272\214\345\215\201\344\270\200\351\242\230.md" "b/Runtime/21.\347\254\254\344\272\214\345\215\201\344\270\200\351\242\230.md" index 44d61bd..0bfd3ed 100644 --- "a/Runtime/21.\347\254\254\344\272\214\345\215\201\344\270\200\351\242\230.md" +++ "b/Runtime/21.\347\254\254\344\272\214\345\215\201\344\270\200\351\242\230.md" @@ -8,3 +8,48 @@ - 如果是无序方法列表,直接遍历查找 +### cache_t结构体 + +```objc +// 缓存曾经调用过的方法,提高查找速率 +struct cache_t { + struct bucket_t *_buckets; // 散列表 + mask_t _mask; //散列表的长度 - 1 + mask_t _occupied; // 已经缓存的方法数量,散列表的长度使大于已经缓存的数量的。 + //... +} +``` + +```objc +struct bucket_t { + cache_key_t _key; //SEL作为Key @selector() + IMP _imp; // 函数的内存地址 + //... +} +``` + +散列表查找过程,在`objc-cache.mm`文件中 + +```objc +// 查询散列表,k +bucket_t * cache_t::find(cache_key_t k, id receiver) +{ + assert(k != 0); // 断言 + + bucket_t *b = buckets(); // 获取散列表 + mask_t m = mask(); // 散列表长度 - 1 + mask_t begin = cache_hash(k, m); // & 操作 + mask_t i = begin; // 索引值 + do { + if (b[i].key() == 0 || b[i].key() == k) { + return &b[i]; + } + } while ((i = cache_next(i, m)) != begin); + // i 的值最大等于mask,最小等于0。 + + // hack + Class cls = (Class)((uintptr_t)this - offsetof(objc_class, cache)); + cache_t::bad_cache(receiver, (SEL)k, cls); +} +``` +上面是查询散列表函数,其中`cache_hash(k, m)`是静态内联方法,将传入的`key`和`mask`进行`&`操作返回`uint32_t`索引值。`do-while`循环查找过程,当发生冲突`cache_next`方法将索引值减1。