block 捕获外部变量,内部调用copy 函数的时机

文章由来:  重新看objc 编译成C++ 时候block 实现时梳理代码时候发现,C++实现的block 内部没找到直接调用__foo_block_impl_0* 这个函数(foo 是定义和实现block 的函数名称,具体看各自测试代block码在哪个函数里面调用的)。

object 代码

// main.m

#import

void foo() {

    int a_int = 0;

    NSNumber *a_number = [NSNumber numberWithInt:0];

    void(^blockA)(void) = ^(void) {

        NSLog(@"a_int = %d", a_int);

        NSLog(@"a_number = %@", a_number);

    };

    a_int = 1;

    a_number = @1;

    blockA();

    return ;

}

int main(int argc, const char * argv[]) {

    foo();

    return 0;

}

对应的C++ 编译之后的主要代码,其他多余代码已经去掉

struct __foo_block_impl_0 {

  struct __block_impl impl;

  struct __foo_block_desc_0* Desc;

  int a_int;

  NSNumber *a_number;

  __foo_block_impl_0(void *fp, struct __foo_block_desc_0 *desc, int _a_int, NSNumber *_a_number, int flags=0) : a_int(_a_int), a_number(_a_number) {

    impl.isa = &_NSConcreteStackBlock;

    impl.Flags = flags;

    impl.FuncPtr = fp;

    Desc = desc;

  }

};

static void __foo_block_func_0(struct __foo_block_impl_0 *__cself) {

  int a_int = __cself->a_int; // bound by copy

  NSNumber *a_number = __cself->a_number; // bound by copy

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_hf_ff518dhs4cq81s4jf93ppmg00000gn_T_blockTest_e6692f_mi_0, a_int);

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_hf_ff518dhs4cq81s4jf93ppmg00000gn_T_blockTest_e6692f_mi_1, a_number);

    }

static void __foo_block_copy_0(struct __foo_block_impl_0*dst, struct __foo_block_impl_0*src) {_Block_object_assign((void*)&dst->a_number, (void*)src->a_number, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static void __foo_block_dispose_0(struct __foo_block_impl_0*src) {_Block_object_dispose((void*)src->a_number, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static struct __foo_block_desc_0 {

  size_t reserved;

  size_t Block_size;

  void (*copy)(struct __foo_block_impl_0*, struct __foo_block_impl_0*);

  void (*dispose)(struct __foo_block_impl_0*);

} __foo_block_desc_0_DATA = { 0, sizeof(struct __foo_block_impl_0), __foo_block_copy_0, __foo_block_dispose_0};

void foo() {

    int a_int = 0;

    NSNumber *a_number = ((NSNumber * _Nonnull (*)(id, SEL, int))(void *)objc_msgSend)((id)objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 0);

    void(*blockA)(void) = ((void (*)())&__foo_block_impl_0((void *)__foo_block_func_0, &__foo_block_desc_0_DATA, a_int, a_number, 570425344));

    a_int = 1;

    a_number = ((NSNumber *(*)(Class, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 1);

    ((void (*)(__block_impl *))((__block_impl *)blockA)->FuncPtr)((__block_impl *)blockA);

    return ;

}

int main(int argc, const char * argv[]) {

    foo();

    return 0;

}

static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

会发现 __foo_block_impl_0 虽然在 __foo_block_desc_0 结构体定义,但是在 __foo_block_impl_0 复制给Desc 时候并没有明显的发现调用__foo_block_impl_0拷贝的痕迹,开始以为在调用block 静态函数__foo_block_func_0 时候给int值变量复制系统会自动调用__foo_block_impl_0之类的,但是后面发现并没有,于是 编译成汇编代码:我们把注意力集中到_foo 函数里面的 ___block_descriptor_44_e8_32s_e5_v8 ,最终调用到 section里面去了,然后在里面执行了___copy_helper_block_e8_32s, 全局搜索下___copy_helper_block_e8_32s 发现 .section    __TEXT,__cstring,cstring_literals 属于代码段字符串符号表定义表达式(.quad,具体自行网上搜索)__copy_helper_block_e8_32s 。 其他地方实在无法联系到调用___copy_helper_block_e8_32s进行拷贝。

    .section    __TEXT,__text,regular,pure_instructions

    .build_version macos, 11, 0    sdk_version 12, 0

    .globl    _foo                            ## -- Begin function foo

    .p2align    4, 0x90

_foo:                                   ## @foo

    .cfi_startproc

## %bb.0:

    pushq    %rbp

    .cfi_def_cfa_offset 16

    .cfi_offset %rbp, -16

    movq    %rsp, %rbp

    .cfi_def_cfa_register %rbp

    subq    $80, %rsp

    xorl    %edx, %edx

    movl    $0, -4(%rbp)

    movq    _OBJC_CLASSLIST_REFERENCES_$_(%rip), %rdi

    movq    _OBJC_SELECTOR_REFERENCES_(%rip), %rsi

    callq    *_objc_msgSend@GOTPCREL(%rip)

    movq    %rax, %rdi

    callq    _objc_retainAutoreleasedReturnValue

    movq    %rax, %rsi

    leaq    "___block_descriptor_44_e8_32s_e5_v8?0l"(%rip), %rax

    leaq    ___foo_block_invoke(%rip), %rcx

    movq    __NSConcreteStackBlock@GOTPCREL(%rip), %rdx

    movq    %rsi, -16(%rbp)

    movq    %rdx, -72(%rbp)

    movl    $-1040187392, -64(%rbp)         ## imm = 0xC2000000

    movl    $0, -60(%rbp)

    movq    %rcx, -56(%rbp)

    movq    %rax, -48(%rbp)

    movl    -4(%rbp), %eax

    movl    %eax, -32(%rbp)

    leaq    -72(%rbp), %rax

    addq    $32, %rax

    movq    %rax, -80(%rbp)                 ## 8-byte Spill

    movq    -16(%rbp), %rdi

    callq    *_objc_retain@GOTPCREL(%rip)

    movq    %rax, -40(%rbp)

    leaq    -72(%rbp), %rdi

    callq    _objc_retainBlock

    leaq    l__unnamed_nsconstantintegernumber_(%rip), %rsi

    movq    %rax, -24(%rbp)

    movl    $1, -4(%rbp)

    leaq    -16(%rbp), %rdi

    callq    _objc_storeStrong

    movq    -24(%rbp), %rax

    movq    %rax, %rdi

    callq    *16(%rax)

    xorl    %eax, %eax

    movl    %eax, %esi

    leaq    -24(%rbp), %rdi

    callq    _objc_storeStrong

    movq    -80(%rbp), %rdi                 ## 8-byte Reload

    xorl    %eax, %eax

    movl    %eax, %esi

    callq    _objc_storeStrong

    xorl    %eax, %eax

    movl    %eax, %esi

    leaq    -16(%rbp), %rdi

    callq    _objc_storeStrong

    addq    $80, %rsp

    popq    %rbp

    retq

    .cfi_endproc

                                        ## -- End function

    .p2align    4, 0x90                        ## -- Begin function __foo_block_invoke

___foo_block_invoke:                    ## @__foo_block_invoke

    .cfi_startproc

## %bb.0:

    pushq    %rbp

    .cfi_def_cfa_offset 16

    .cfi_offset %rbp, -16

    movq    %rsp, %rbp

    .cfi_def_cfa_register %rbp

    subq    $32, %rsp

    movq    %rdi, %rax

    movq    %rax, -24(%rbp)                 ## 8-byte Spill

    leaq    L__unnamed_cfstring_(%rip), %rdi

    movq    %rax, -8(%rbp)

    movq    %rax, %rcx

    movq    %rcx, -16(%rbp)

    movl    40(%rax), %esi

    movb    $0, %al

    callq    _NSLog

    movq    -24(%rbp), %rax                 ## 8-byte Reload

    leaq    L__unnamed_cfstring_.2(%rip), %rdi

    movq    32(%rax), %rsi

    movb    $0, %al

    callq    _NSLog

    addq    $32, %rsp

    popq    %rbp

    retq

    .cfi_endproc

                                        ## -- End function

    .private_extern    ___copy_helper_block_e8_32s ## -- Begin function __copy_helper_block_e8_32s

    .globl    ___copy_helper_block_e8_32s

    .weak_def_can_be_hidden    ___copy_helper_block_e8_32s

    .p2align    4, 0x90

___copy_helper_block_e8_32s:            ## @__copy_helper_block_e8_32s

    .cfi_startproc

## %bb.0:

    pushq    %rbp

    .cfi_def_cfa_offset 16

    .cfi_offset %rbp, -16

    movq    %rsp, %rbp

    .cfi_def_cfa_register %rbp

    subq    $16, %rsp

    movq    %rdi, -8(%rbp)

    movq    %rsi, -16(%rbp)

    movq    -16(%rbp), %rcx

    movq    -8(%rbp), %rax

    movq    %rax, %rdi

    addq    $32, %rdi

    movq    32(%rcx), %rsi

    movq    $0, 32(%rax)

    callq    _objc_storeStrong

    addq    $16, %rsp

    popq    %rbp

    retq

    .cfi_endproc

                                        ## -- End function

    .private_extern    ___destroy_helper_block_e8_32s ## -- Begin function __destroy_helper_block_e8_32s

    .globl    ___destroy_helper_block_e8_32s

    .weak_def_can_be_hidden    ___destroy_helper_block_e8_32s

    .p2align    4, 0x90

___destroy_helper_block_e8_32s:         ## @__destroy_helper_block_e8_32s

    .cfi_startproc

## %bb.0:

    pushq    %rbp

    .cfi_def_cfa_offset 16

    .cfi_offset %rbp, -16

    movq    %rsp, %rbp

    .cfi_def_cfa_register %rbp

    subq    $16, %rsp

    xorl    %eax, %eax

    movl    %eax, %esi

    movq    %rdi, -8(%rbp)

    movq    -8(%rbp), %rdi

    addq    $32, %rdi

    callq    _objc_storeStrong

    addq    $16, %rsp

    popq    %rbp

    retq

    .cfi_endproc

                                        ## -- End function

    .globl    _main                           ## -- Begin function main

    .p2align    4, 0x90

_main:                                  ## @main

    .cfi_startproc

## %bb.0:

    pushq    %rbp

    .cfi_def_cfa_offset 16

    .cfi_offset %rbp, -16

    movq    %rsp, %rbp

    .cfi_def_cfa_register %rbp

    subq    $16, %rsp

    movl    $0, -4(%rbp)

    movl    %edi, -8(%rbp)

    movq    %rsi, -16(%rbp)

    callq    _foo

    xorl    %eax, %eax

    addq    $16, %rsp

    popq    %rbp

    retq

    .cfi_endproc

                                        ## -- End function

    .section    __DATA,__objc_classrefs,regular,no_dead_strip

    .p2align    3                              ## @"OBJC_CLASSLIST_REFERENCES_$_"

_OBJC_CLASSLIST_REFERENCES_$_:

    .quad    _OBJC_CLASS_$_NSNumber

    .section    __TEXT,__objc_methname,cstring_literals

L_OBJC_METH_VAR_NAME_:                  ## @OBJC_METH_VAR_NAME_

    .asciz    "numberWithInt:"

    .section    __DATA,__objc_selrefs,literal_pointers,no_dead_strip

    .p2align    3                              ## @OBJC_SELECTOR_REFERENCES_

_OBJC_SELECTOR_REFERENCES_:

    .quad    L_OBJC_METH_VAR_NAME_

    .section    __TEXT,__cstring,cstring_literals

L_.str:                                 ## @.str

    .asciz    "a_int = %d"

    .section    __DATA,__cfstring

    .p2align    3                              ## @_unnamed_cfstring_

L__unnamed_cfstring_:

    .quad    ___CFConstantStringClassReference

    .long    1992                            ## 0x7c8

    .space    4

    .quad    L_.str

    .quad    10                              ## 0xa

    .section    __TEXT,__cstring,cstring_literals

L_.str.1:                               ## @.str.1

    .asciz    "a_number = %@"

    .section    __DATA,__cfstring

    .p2align    3                              ## @_unnamed_cfstring_.2

L__unnamed_cfstring_.2:

    .quad    ___CFConstantStringClassReference

    .long    1992                            ## 0x7c8

    .space    4

    .quad    L_.str.1

    .quad    13                              ## 0xd

    .section    __TEXT,__cstring,cstring_literals

L_.str.3:                               ## @.str.3

    .asciz    "v8@?0"

    .private_extern    "___block_descriptor_44_e8_32s_e5_v8?0l" ## @"__block_descriptor_44_e8_32s_e5_v8\01?0l"

    .section    __DATA,__const

    .globl    "___block_descriptor_44_e8_32s_e5_v8?0l"

    .weak_def_can_be_hidden    "___block_descriptor_44_e8_32s_e5_v8?0l"

    .p2align    3

"___block_descriptor_44_e8_32s_e5_v8?0l":

    .quad    0                              ## 0x0

    .quad    44                              ## 0x2c

    .quad    ___copy_helper_block_e8_32s

    .quad    ___destroy_helper_block_e8_32s

    .quad    L_.str.3

    .quad    256                            ## 0x100

    .section    __TEXT,__cstring,cstring_literals

L_.str.4:                               ## @.str.4

    .asciz    "i"

    .section    __DATA,__objc_intobj,regular,no_dead_strip

    .p2align    3                              ## @_unnamed_nsconstantintegernumber_

l__unnamed_nsconstantintegernumber_:

    .quad    _OBJC_CLASS_$_NSConstantIntegerNumber

    .quad    L_.str.4

    .quad    1                              ## 0x1

    .section    __DATA,__objc_imageinfo,regular,no_dead_strip

L_OBJC_IMAGE_INFO:

    .long    0

    .long    64

.subsections_via_symbols

目前大概明白了通过传结构体值时发生了参数拷贝,本人对C++不是很熟悉,不是很了解到底C++内部是如何传调用copy函数,只能通过汇编跳转猜测应该是在block 内部赋值DESC 时候进行拷贝(可以当参考思路不能当正确答案,不敢胡乱猜测 !-_-!)。

你可能感兴趣的:(block 捕获外部变量,内部调用copy 函数的时机)