llvm中Block的实现

一个block主要的结构如下:


struct Block_literal_1 {
    void *isa; // 初始化为 &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor_1 {
    unsigned long int reserved;         // NULL
        unsigned long int size;         // sizeof(struct Block_literal_1)
        // optional helper functions
        void (*copy_helper)(void *dst, void *src);     // IFF (1<<25)
        void (*dispose_helper)(void *src);             // IFF (1<<25)
        // required ABI.2010.3.16
        const char *signature;                         // IFF (1<<30)
    } *descriptor;
    // 引用的变量...
};

When a Block literal expression is evaluated the stack based structure is initialized as follows:

  1. 声明一个static descriptor,并且按照下面方式初始化:
  • invoke函数指针指向一个以Block作为第一个参数、Block参数作为其余参数的函数,函数体是block的函数体。

  • size设置成Block literal结构体的大小

  • copy_helper 和 dispose_helper指针设置为Block literal需要的对应helper函数.

  1. 一个stack (或global) Block literal 的数据结构按照下面的方式进行创建和初始化:
  • isa 设置为_NSConcreteStackBlock的地址,或者是_NSConcreteGlobalBlock的地址(如果Block是static或file level).
  • flags通常设置为0,除非block截获的变量需要helper函数(Block_copy() 和 Block_release() )operations.

引入变量(Imported Variables)

auto storage class的变量会作为const copies在block中使用。__block storage class的变量作为一个指向数据结构的指针被引入使用。全局的变量仅仅作为引用,不被看作是被引入。

比如下面的代码:

int x = 10;
void (^vv)(void) = ^{ printf("x is %d\n", x); }
x = 11;
vv();

被编译成:

struct __block_literal_2 {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(struct __block_literal_2 *);
    struct __block_descriptor_2 *descriptor;
    const int x;
};

void __block_invoke_2(struct __block_literal_2 *_block) {
    printf("x is %d\n", _block->x);
}

static struct __block_descriptor_2 {
    unsigned long int reserved;
    unsigned long int Block_size;
} __block_descriptor_2 = { 0, sizeof(struct __block_literal_2) };;

struct __block_literal_2 __block_literal_2 = {
      &_NSConcreteStackBlock,
      (1<<29), ,
      __block_invoke_2,
      &__block_descriptor_2,
      x
 };

scalars、structures、unions和函数指针作为const copies引入block,不需要helper函数。

引入attribute((NSObject))变量

GCC针对结构体引入了attribute((NSObject))来表示这个结构体指针是一个对象。因为许多底层的数据结构被声明为opague structure指针,比如CGStringRef、CFArrayRef。从C转换过来时,它们其实就是对象。需要生成针对它们的copy和dispose函数。

比如下面的例子:

struct Opaque *__attribute__((NSObject)) objectPointer = ...;
...
void (^foo)(void) = ^{  CFPrint(objectPointer); };

会编译出下面的helper function:

void __block_copy_foo(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
     _Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
}

void __block_dispose_foo(struct __block_literal_5 *src) {
     _Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
}

引入__block变量

编译器会将__block标示的变量编译成如下结构:

struct _block_byref_foo {
    void *isa;
    struct Block_byref *forwarding;
    int flags;   //refcount;
    int size;
    typeof(marked_variable) marked_variable;
};

当针对一个block之行Block_copy或Block_release时,一些特定的类型变量需要helper函数。在C语言层次,只有Block类型或者_attribute((NSObject))类型会有helper函数。OC对象都需要helper函数,C++基于stack的对象需要helper函数。拥有helper函数的变量会编译成下面的形式:

struct _block_byref_foo {
    void *isa;
    struct _block_byref_foo *forwarding;
    int flags;   //refcount;
    int size;
    // helper functions called via Block_copy() and Block_release()
    void (*byref_keep)(void  *dst, void *src);
    void (*byref_dispose)(void *);
    typeof(marked_variable) marked_variable;
};

其初始化过程如下:

  • forwarding指针指向结构体的开头
  • size设置为结构题的大小
  • flags设置为0,有helper函数时设置为1<<25
  • helper函数初始化
  • 变量设置为初始值
  • isa设置为NULL

在lexical scope内访问__block变量

当执行copy_helper是,为了将变量“移动”到堆上,编译器必须将对这个变量的访问重写成间接访问结构体的forwarding指针。比如:

int __block i = 10;
i = 11;

会编译成:

struct _block_byref_i {
  void *isa;
  struct _block_byref_i *forwarding;
  int flags;   //refcount;
  int size;
  int captured_i;
} i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 };

i.forwarding->captured_i = 11;

如果一个Block引用的变量被标记为__block,会生成helper函数。比如:

__block void (voidBlock)(void) = blockA;
voidBlock = blockB;

会编译成:

struct _block_byref_voidBlock {
    void *isa;
    struct _block_byref_voidBlock *forwarding;
    int flags;   //refcount;
    int size;
    void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
    void (*byref_dispose)(struct _block_byref_voidBlock *);
    void (^captured_voidBlock)(void);
};

void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
    //_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
    _Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
}

void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
    //_Block_destroy(param->captured_voidBlock, 0);
    _Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
    
    struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
    .byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
    .captured_voidBlock=blockA )};

voidBlock.forwarding->captured_voidBlock = blockB;

将__block变量引入blocks中

如果一个block使用了__block变量,它必须生成copy_helper和dispose_helper。比如:

int __block i = 2;
functioncall(^{ i = 10; });

会被编译成:


struct _block_byref_i {
    void *isa;  // set to NULL
    struct _block_byref_voidBlock *forwarding;
    int flags;   //refcount;
    int size;
    void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
    void (*byref_dispose)(struct _block_byref_i *);
    int captured_i;
};


struct __block_literal_5 {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(struct __block_literal_5 *);
    struct __block_descriptor_5 *descriptor;
    struct _block_byref_i *i_holder;
};

void __block_invoke_5(struct __block_literal_5 *_block) {
   _block->forwarding->captured_i = 10;
}

void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
     //_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
     _Block_object_assign(&dst->captured_i, src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}

void __block_dispose_5(struct __block_literal_5 *src) {
     //_Block_byref_release(src->captured_i);
     _Block_object_dispose(src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}

static struct __block_descriptor_5 {
    unsigned long int reserved;
    unsigned long int Block_size;
    void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
    void (*dispose_helper)(struct __block_literal_5 *);
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };


//对应的编译代码
struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
struct __block_literal_5 _block_literal = {
      &_NSConcreteStackBlock,
      (1<<25)|(1<<29), ,
      __block_invoke_5,
      &__block_descriptor_5,
      2,
};

你可能感兴趣的:(llvm中Block的实现)