Block解析_1

  本文翻译原文:http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-1/

点击打开链接

           对于Block的内部实现:第一部分

       今天我已经观察过Block从编译器的角度来看它是怎么工作的。通过Block,我认为苹果加到C语言的闭包函数很不错同时从编译器的角度来说的确成功成为C语言的一部分。我曾经好奇过什么是Block,它是怎么神奇的会成为一个OC的对象(你可以retain,copy,release一个实力对象),这篇文章主要就是对Block进行探讨。
      基本的:
void(^block)(void) = ^{
        
        NSLog(@"I am a block");
        
    };
      刚刚创建了一个变量"block"并且给它赋值了一个block,这个操作很简单是吗?不,我更想知道的是编译器对于这段代码做了什么。
     现在给block添加一个变量
    
void(^block1)(int) = ^(int a){
      
        NSLog(@"I am a block a = %d", a);
    };
     或者甚至给个返回值
  
int(^block2)(void) = ^{
        
        NSLog(@"I am a block");
        return 1;
        
    };

     深入来看一个简单的例子

    我的第一个想法就是看看编译器是如何编译一个简单的block的,思考一下以下这段代码
typedef void(^BlockA)(void);

__attribute__((noinline))
void runBlockA(BlockA block){
    block();
}

void doBlockA(){
    
    BlockA block = ^{
      
        //empty block
    };
    
    runBlockA(block);
}
     建立两个函数的原因就是我想知道block是如何被调用的,还有它是如何创建的。如果它们在一个函数里面的话优化器可能会做一些处理,我们就看不到到底发生了什么。我已经把runBlockA变成了无内联关系,因此优化器不会内联doBlockA里的那个函数,这样做减少了同样的问题。

       代码相关的编译信息如下(armv7,03)


      这个是runBlockA函数,这个非常简单。现在倒回去看一看,这个函数仅仅是调用了block。r0(寄存器r0)里面放入了函数的第一个参数。因此第一条指令的意思就是r1载入的值是r0+12个单元里存放的值。把这个当做加了12个字节指针的解引用。我们现在转移到这个地址.注意到r1被使用了,那么r0里面一定是block本身。这样看来这里正在调用的这个函数把block当做了它的第一个参数。
      从这一点上,我可以确定block很可能是某种结构,该结构的功能块应该执行的是存储12字节到上述结构。当一个block被传递的时候,只是传递此结构里的一个指针。
      现在来看看doBlockA这个方法


      这个同样很简单。这是一个程序计数器相对的载入。你可以当成仅仅是载入一个叫做__block_literal_global的一个变量到r0中。接下来runBlockA函数被调用了。所以我们知道block对象被传递给了runBlockA,这个__block_literal_global一定就是block对象。
      现在已经取得了一些进展。但是__block_literal_global精确来说是什么。

                                        

       这非常像一个结构体,这个结构体里面有5个4字节长的值,这一定就是runBlockA起作用的那个block。结构体中的12个字节是那个看起来像个函数指针它叫做__doBlockA_block_invoke_0。记住这就是runBlockA跳转的。
       但是什么是NSConcreteGlobalBlock,__doBlockA_block_invoke_0和__block_descriptor_tmp很有趣,它们同样出现了下面的文件中。


       __doBlockA_block_invoke_0看起来像一个实现它自己的的block,因为我们使用的是一个空的block。这个函数立刻返回了,正如我们预计空函数是如何编译的那样。
       接下来看一看__block_descriptor_tmp,这次似乎出现了另一种结构体,这次里面有四个值。第二个值20表示__block_literal_global是多大,这可能是一个容量值?还有一个C语言的字符串叫.str,它的值是v4@?0。这看起来像一种形式的编码。这可能是block形式的编码(没有返回值没有参数)。另一个值我也不知道是干吗的。
      但是源头就在那里不是吗?
      这个是LLVM项目compiler-rt分析的block头文Block_private.h头文件中关于Block的struct声明:


         这看起来多么的熟悉,Block_Layout结构体就是__block_literal_global所指,Block_descriptor结构体就是__block_descriptor_tmp所指。
              Block_layout中的isa指针非常有意思,因为他就是_NSConcreteBlock所指,同样还是block怎么样仿真成为一个OC对象的真相。如果_NSConcreteBlock是一个类,那么OC的消息传递机制很乐于将block当做一个普通的对象对待,这很像Toll Free Bridging点击打开链接
           把之前那些全部都拼起来看,编译器对于这些代码做了这些事情:


     




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值