objc_msgSend函数的实现
毕竟汇编语言代码比较晦涩难懂,因此这里将函数的实现反汇编成C语言的伪代码:
//下面的结构体中只列出objc_msgSend函数内部访问用到的那些数据结构和成员。
/*
其实SEL类型就是一个字符串指针类型,所描述的就是方法字符串指针
*/
typedef char * SEL;
/*
IMP类型就是所有OC方法的函数原型类型。
*/
typedef id (*IMP)(id self, SEL _cmd, ...);
/*
objc_msgSend的C语言版本伪代码实现.
receiver: 是调用方法的对象
op: 是要调用的方法名称字符串
*/
id objc_msgSend(id receiver, SEL op, ...)
{
//1............................ 对象空值判断。
//如果传入的对象是nil则直接返回nil
if (receiver == nil)
return nil;
//2............................ 获取或者构造对象的isa数据。
void *isa = NULL;
//如果对象的地址最高位为0则表明是普通的OC对象,否则就是Tagged Pointer类型的对象
if ((receiver & 0x8000000000000000) == 0) {
struct objc_object *ocobj = (struct objc_object*) receiver;
isa = ocobj->isa;
}
else { //Tagged Pointer类型的对象中没有直接保存isa数据,所以需要特殊处理来查找对应的isa数据。
//如果对象地址的最高4位为0xF, 那么表示是一个用户自定义扩展的Tagged Pointer类型对象
if (((NSUInteger) receiver) >= 0xf000000000000000) {
//自定义扩展的Tagged Pointer类型对象中的52-59位保存的是一个全局扩展Tagged Pointer类数组的索引值。
int classidx = (receiver & 0xFF0000000000000) >> 52
isa = objc_debug_taggedpointer_ext_classes[classidx];
}
else {
//系统自带的Tagged Pointer类型对象中的60-63位保存的是一个全局Tagged Pointer类数组的索引值。
int classidx = ((NSUInteger) receiver) >> 60;
isa = objc_debug_taggedpointer_classes[classidx];
}
}
//因为内存地址对齐的原因和虚拟内存空间的约束原因,
//以及isa定义的原因需要将isa与上0xffffffff8才能得到对象所属的Class对象。
struct objc_class *cls = (struct objc_class *)(isa & 0xffffffff8);
//3............................ 遍历缓存哈希桶并查找缓存中的方法实现。
IMP imp = NULL;
//cmd与cache中的mask进行与计算得到哈希桶中的索引,来查找方法是否已经放入缓存cache哈希桶中。
int index = cls->cache.mask & op;
while (true) {
//如果缓存哈希桶中命中了对应的方法实现,则保存到imp中并退出循环。
if (cls->cache.buckets[index].key == op) {
imp = cls->cache.buckets[index].imp;
break;
}
//方法实现并没有被缓存,并且对应的桶的数据是空的就退出循环
if (cls->cache.buckets[index].key == NULL) {
break;
}
//如果哈希桶中对应的项已经被占用但是又不是要执行的方法,则通过开地址法来继续寻找缓存该方法的桶。
if (index == 0) {
index = cls->cache.mask; //从尾部寻找
}
else {
index--; //索引减1继续寻找。
}
} /*end while*/
//4............................ 执行方法实现或方法未命中缓存处理函数
if (imp != NULL)
return imp(receiver, op, ...); //这里的... 是指传递给objc_msgSend的OC方法中的参数。
else
return objc_msgSend_uncached(receiver, op, cls, ...);
}
/*
方法未命中缓存处理函数:objc_msgSend_uncached的C语言版本伪代码实现,这个函数也是用汇编语言编写。
*/
id objc_msgSend_uncached(id receiver, SEL op, struct objc_class *cls)
{
//这个函数很简单就是直接调用了_class_lookupMethodAndLoadCache3 来查找方法并缓存到struct objc_class中的cache中,最后再返回IMP类型。
IMP imp = _class_lookupMethodAndLoadCache3(receiver, op, cls);
return imp(receiver, op, ....);
}
https://www.jianshu.com/p/df6629ec9a25
相关文章
- C语言atoi()和itoa()函数的实现
- Java实现 蓝桥杯 算法训练 Rotatable Number(暴力)
- Java实现 蓝桥杯 历届真题 稍大的串
- Java实现 蓝桥杯VIP 算法提高 欧拉函数
- Java实现 蓝桥杯VIP 算法提高 欧拉函数
- Java实现 蓝桥杯VIP 算法提高 去注释
- (Java实现) 光荣的梦想
- R语言实现金融数据的时间序列分析及建模
- (C++)已知String类的定义,实现其函数体
- python禁止函数修改列表的实现方法
- 又一位纯手工打造CPU的牛人,并汇编实现类Unix系统,支持文件系统
- java 实现将Object类型转换为int类型
- 基于JAVA实现的WEB端UI自动化 - WebDriver高级篇 - 代码检查点[验证点/断言]与图像检查点
- 【优化调度】基于改进遗传算法的公交车调度排班优化的研究与实现(Matlab代码实现)
- 使用星凸随机超曲面模型对扩展对象和分组目标进行形状跟踪(Matlab代码实现)
- Android NDK 实现视音频播放器源码
- 利用函数指针实现C的回调函数,实现调用者和底层驱动的解耦 第二种方式
- 基于simulink的MPPT控制器性能仿真,MPPT使用S函数实现
- 线程的概念 线程和进程的比较 多线程的用处 线程的基本操作 线程的创建 验证多线程实现多任务 及线程间共享全局变量 验证线程函数传参 collect2: error: ld returned 1 e
- 【LeetCode Python实现】300. 最长递增子序列(中等)动态规划
- 1318. 或运算的最小翻转次数-c语言函数实现
- 【数字信号处理】卷积编程实现 ( Matlab 卷积和多项式乘法 conv 函数 | 使用 matlab 代码求卷积并绘图 )
- 一个ip对应多个域名多个ssl证书配置-Nginx实现多域名证书HTTPS
- VL19-使用38译码器实现逻辑函数!L=(~A)·C+A·B
- reactos操作系统实现(175)