Skip to content

Commit

Permalink
补充isa
Browse files Browse the repository at this point in the history
  • Loading branch information
jesusLove committed Sep 12, 2018
1 parent eefb395 commit 37964b8
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 10 deletions.
7 changes: 7 additions & 0 deletions Runtime/1.第一题.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@

具体可以参看 `Runtime` 源代码,在文件 `objc-private.h` 的第 `127-232` 行。

```
struct objc_object {
isa_t isa;
//...
}
```

本质上 `objc_object` 的私有属性只有一个 `isa` 指针。指向 `类对象` 的内存地址。

54 changes: 54 additions & 0 deletions Runtime/10.第十题.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

}
```

> 注意:什么是位域?
22 changes: 16 additions & 6 deletions Runtime/13.第十三题.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

//...
}
```
2 changes: 2 additions & 0 deletions Runtime/14.第十四题.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ struct class_ro_t {
};
```

`baseMethodList``baseProtocols``ivars``baseProperties`三个都是以为数组。


21 changes: 17 additions & 4 deletions Runtime/2.第二题.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`



45 changes: 45 additions & 0 deletions Runtime/21.第二十一题.md
Original file line number Diff line number Diff line change
Expand Up @@ -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。

0 comments on commit 37964b8

Please sign in to comment.