block底层实现原理

objc含block的源代码

#include"stdio.h"
int main()
{
        void (^blk)(void) = ^{printf("Block.\n");};
    blk();
    return 0;

}

将此源代码clang变换成底层C代码:(clang-rewrite-objc main.m)

#ifndef __OBJC2__
#define __OBJC2__
#endif
struct objc_selector; struct objc_class;
struct __rw_objc_super {
    struct objc_object *object;
    struct objc_object *superClass;
    __rw_objc_super(struct objc_object *o, struct objc_object *s) : object(o), superClass(s) {}
};
#ifndef _REWRITER_typedef_Protocol
typedef struct objc_object Protocol;
#define _REWRITER_typedef_Protocol
#endif
#define __OBJC_RW_DLLIMPORT extern
__OBJC_RW_DLLIMPORT void objc_msgSend(void);
__OBJC_RW_DLLIMPORT void objc_msgSendSuper(void);
__OBJC_RW_DLLIMPORT void objc_msgSend_stret(void);
__OBJC_RW_DLLIMPORT void objc_msgSendSuper_stret(void);
__OBJC_RW_DLLIMPORT void objc_msgSend_fpret(void);
__OBJC_RW_DLLIMPORT struct objc_class *objc_getClass(const char *);
__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass(struct objc_class *);
__OBJC_RW_DLLIMPORT struct objc_class *objc_getMetaClass(const char *);
__OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);
__OBJC_RW_DLLIMPORT int objc_sync_enter( struct objc_object *);
__OBJC_RW_DLLIMPORT int objc_sync_exit( struct objc_object *);
__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);
#ifdef _WIN64
typedef unsigned long long  _WIN_NSUInteger;
#else
typedef unsigned int _WIN_NSUInteger;
#endif
#ifndef __FASTENUMERATIONSTATE
struct __objcFastEnumerationState {
    unsigned long state;
    void **itemsPtr;
    unsigned long *mutationsPtr;
    unsigned long extra[5];
};
__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);
#define __FASTENUMERATIONSTATE
#endif
#ifndef __NSCONSTANTSTRINGIMPL
struct __NSConstantStringImpl {
    int *isa;
    int flags;
    char *str;
    long length;
};
#ifdef CF_EXPORT_CONSTANT_STRING
extern "C" __declspec(dllexport) int __CFConstantStringClassReference[];
#else
__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];
#endif
#define __NSCONSTANTSTRINGIMPL
#endif
#ifndef BLOCK_IMPL
#define BLOCK_IMPL
struct __block_impl {
    void *isa;
    int Flags;
    int Reserved;
    void *FuncPtr;
};
// Runtime copy/destroy helper functions (from Block_private.h)
#ifdef __OBJC_EXPORT_BLOCKS
extern "C" __declspec(dllexport) void _Block_object_assign(void *, const void *, const int);
extern "C" __declspec(dllexport) void _Block_object_dispose(const void *, const int);
extern "C" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];
extern "C" __declspec(dllexport) void *_NSConcreteStackBlock[32];
#else
__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);
__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);
__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];
__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];
#endif
#endif
#define __block
#define __weak

#include <stdarg.h>
struct __NSContainer_literal {
    void * *arr;
    __NSContainer_literal (unsigned int count, ...) {
        va_list marker;
        va_start(marker, count);
        arr = new void *[count];
        for (unsigned i = 0; i < count; i++)
            arr[i] = va_arg(marker, void *);
        va_end( marker );
    };
    ~__NSContainer_literal() {
        delete[] arr;
    }
};
extern "C" __declspec(dllimport) void * objc_autoreleasePoolPush(void);
extern "C" __declspec(dllimport) void objc_autoreleasePoolPop(void *);

struct __AtAutoreleasePool {
    __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
    ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
    void * atautoreleasepoolobj;
};

#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)

typedef signed char __int8_t;



typedef unsigned char __uint8_t;
typedef short __int16_t;
typedef unsigned short __uint16_t;
typedef int __int32_t;
typedef unsigned int __uint32_t;
typedef long long __int64_t;
typedef unsigned long long __uint64_t;

typedef long __darwin_intptr_t;
typedef unsigned int __darwin_natural_t;
typedef int __darwin_ct_rune_t;





typedef union {
    char __mbstate8[128];
    long long _mbstateL;
} __mbstate_t;

typedef __mbstate_t __darwin_mbstate_t;


typedef long int __darwin_ptrdiff_t;







typedef long unsigned int __darwin_size_t;





typedef __builtin_va_list __darwin_va_list;





typedef int __darwin_wchar_t;




typedef __darwin_wchar_t __darwin_rune_t;


typedef int __darwin_wint_t;




typedef unsigned long __darwin_clock_t;
typedef __uint32_t __darwin_socklen_t;
typedef long __darwin_ssize_t;
typedef long __darwin_time_t;
typedef __int64_t __darwin_blkcnt_t;
typedef __int32_t __darwin_blksize_t;
typedef __int32_t __darwin_dev_t;
typedef unsigned int __darwin_fsblkcnt_t;
typedef unsigned int __darwin_fsfilcnt_t;
typedef __uint32_t __darwin_gid_t;
typedef __uint32_t __darwin_id_t;
typedef __uint64_t __darwin_ino64_t;

typedef __darwin_ino64_t __darwin_ino_t;



typedef __darwin_natural_t __darwin_mach_port_name_t;
typedef __darwin_mach_port_name_t __darwin_mach_port_t;
typedef __uint16_t __darwin_mode_t;
typedef __int64_t __darwin_off_t;
typedef __int32_t __darwin_pid_t;
typedef __uint32_t __darwin_sigset_t;
typedef __int32_t __darwin_suseconds_t;
typedef __uint32_t __darwin_uid_t;
typedef __uint32_t __darwin_useconds_t;
typedef unsigned char __darwin_uuid_t[16];
typedef char __darwin_uuid_string_t[37];


struct __darwin_pthread_handler_rec {
    void (*__routine)(void *);
    void *__arg;
    struct __darwin_pthread_handler_rec *__next;
};

struct _opaque_pthread_attr_t {
    long __sig;
    char __opaque[56];
};

struct _opaque_pthread_cond_t {
    long __sig;
    char __opaque[40];
};

struct _opaque_pthread_condattr_t {
    long __sig;
    char __opaque[8];
};

struct _opaque_pthread_mutex_t {
    long __sig;
    char __opaque[56];
};

struct _opaque_pthread_mutexattr_t {
    long __sig;
    char __opaque[8];
};

struct _opaque_pthread_once_t {
    long __sig;
    char __opaque[8];
};

struct _opaque_pthread_rwlock_t {
    long __sig;
    char __opaque[192];
};

struct _opaque_pthread_rwlockattr_t {
    long __sig;
    char __opaque[16];
};

struct _opaque_pthread_t {
    long __sig;
    struct __darwin_pthread_handler_rec *__cleanup_stack;
    char __opaque[8176];
};

typedef struct _opaque_pthread_attr_t __darwin_pthread_attr_t;
typedef struct _opaque_pthread_cond_t __darwin_pthread_cond_t;
typedef struct _opaque_pthread_condattr_t __darwin_pthread_condattr_t;
typedef unsigned long __darwin_pthread_key_t;
typedef struct _opaque_pthread_mutex_t __darwin_pthread_mutex_t;
typedef struct _opaque_pthread_mutexattr_t __darwin_pthread_mutexattr_t;
typedef struct _opaque_pthread_once_t __darwin_pthread_once_t;
typedef struct _opaque_pthread_rwlock_t __darwin_pthread_rwlock_t;
typedef struct _opaque_pthread_rwlockattr_t __darwin_pthread_rwlockattr_t;
typedef struct _opaque_pthread_t *__darwin_pthread_t;
typedef int __darwin_nl_item;
typedef int __darwin_wctrans_t;

typedef __uint32_t __darwin_wctype_t;



typedef __darwin_va_list va_list;
typedef __darwin_size_t size_t;

extern "C" {
    
    int renameat(int, const char *, int, const char *) __attribute__((availability(macosx,introduced=10.10)));
    
}

typedef __darwin_off_t fpos_t;
struct __sbuf {
    unsigned char *_base;
    int _size;
};


struct __sFILEX;
typedef struct __sFILE {
    unsigned char *_p;
    int _r;
    int _w;
    short _flags;
    short _file;
    struct __sbuf _bf;
    int _lbfsize;
    
    
    void *_cookie;
    int (*_close)(void *);
    int (*_read) (void *, char *, int);
    fpos_t (*_seek) (void *, fpos_t, int);
    int (*_write)(void *, const char *, int);
    
    
    struct __sbuf _ub;
    struct __sFILEX *_extra;
    int _ur;
    
    
    unsigned char _ubuf[3];
    unsigned char _nbuf[1];
    
    
    struct __sbuf _lb;
    
    
    int _blksize;
    fpos_t _offset;
} FILE;

extern "C" {
    extern FILE *__stdinp;
    extern FILE *__stdoutp;
    extern FILE *__stderrp;
}
extern "C" {
    void clearerr(FILE *);
    int fclose(FILE *);
    int feof(FILE *);
    int ferror(FILE *);
    int fflush(FILE *);
    int fgetc(FILE *);
    int fgetpos(FILE * , fpos_t *);
    char *fgets(char * , int, FILE *);
    
    
    
    FILE *fopen(const char * , const char * ) __asm("_" "fopen");
    
    int fprintf(FILE * , const char * , ...) __attribute__((__format__ (__printf__, 2, 3)));
    int fputc(int, FILE *);
    int fputs(const char * , FILE * ) __asm("_" "fputs") ;
    size_t fread(void * , size_t, size_t, FILE * );
    FILE *freopen(const char * , const char * ,
                  FILE * ) __asm("_" "freopen") ;
    int fscanf(FILE * , const char * , ...) __attribute__((__format__ (__scanf__, 2, 3)));
    int fseek(FILE *, long, int);
    int fsetpos(FILE *, const fpos_t *);
    long ftell(FILE *);
    size_t fwrite(const void * , size_t, size_t, FILE * ) __asm("_" "fwrite") ;
    int getc(FILE *);
    int getchar(void);
    char *gets(char *);
    void perror(const char *);
    int printf(const char * , ...) __attribute__((__format__ (__printf__, 1, 2)));
    int putc(int, FILE *);
    int putchar(int);
    int puts(const char *);
    int remove(const char *);
    int rename (const char *, const char *);
    void rewind(FILE *);
    int scanf(const char * , ...) __attribute__((__format__ (__scanf__, 1, 2)));
    void setbuf(FILE * , char * );
    int setvbuf(FILE * , char * , int, size_t);
    int sprintf(char * , const char * , ...) __attribute__((__format__ (__printf__, 2, 3)));
    int sscanf(const char * , const char * , ...) __attribute__((__format__ (__scanf__, 2, 3)));
    FILE *tmpfile(void);
    
    
    __attribute__((deprecated("This function is provided for compatibility reasons only.  Due to security concerns inherent in the design of tmpnam(3), it is highly recommended that you use mkstemp(3) instead.")))
    
    char *tmpnam(char *);
    int ungetc(int, FILE *);
    int vfprintf(FILE * , const char * , va_list) __attribute__((__format__ (__printf__, 2, 0)));
    int vprintf(const char * , va_list) __attribute__((__format__ (__printf__, 1, 0)));
    int vsprintf(char * , const char * , va_list) __attribute__((__format__ (__printf__, 2, 0)));
}
extern "C" {
    
    
    
    char *ctermid(char *);
    
    
    
    
    
    FILE *fdopen(int, const char *) __asm("_" "fdopen");
    
    int fileno(FILE *);
}
extern "C" {
    int pclose(FILE *);
    
    
    
    FILE *popen(const char *, const char *) __asm("_" "popen");
    
}
extern "C" {
    int __srget(FILE *);
    int __svfscanf(FILE *, const char *, va_list) __attribute__((__format__ (__scanf__, 2, 0)));
    int __swbuf(int, FILE *);
}







inline __attribute__ ((__always_inline__)) int __sputc(int _c, FILE *_p) {
    if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
        return (*_p->_p++ = _c);
    else
        return (__swbuf(_c, _p));
}
extern "C" {
    void flockfile(FILE *);
    int ftrylockfile(FILE *);
    void funlockfile(FILE *);
    int getc_unlocked(FILE *);
    int getchar_unlocked(void);
    int putc_unlocked(int, FILE *);
    int putchar_unlocked(int);
    
    
    
    int getw(FILE *);
    int putw(int, FILE *);
    
    
    
    __attribute__((deprecated("This function is provided for compatibility reasons only.  Due to security concerns inherent in the design of tempnam(3), it is highly recommended that you use mkstemp(3) instead.")))
    
    char *tempnam(const char *, const char *) __asm("_" "tempnam") ;
}
typedef __darwin_off_t off_t;

extern "C" {
    int fseeko(FILE *, off_t, int);
    off_t ftello(FILE *);
}



extern "C" {
    int snprintf(char * , size_t, const char * , ...) __attribute__((__format__ (__printf__, 3, 4)));
    int vfscanf(FILE * , const char * , va_list) __attribute__((__format__ (__scanf__, 2, 0)));
    int vscanf(const char * , va_list) __attribute__((__format__ (__scanf__, 1, 0)));
    int vsnprintf(char * , size_t, const char * , va_list) __attribute__((__format__ (__printf__, 3, 0)));
    int vsscanf(const char * , const char * , va_list) __attribute__((__format__ (__scanf__, 2, 0)));
}
typedef __darwin_ssize_t ssize_t;

extern "C" {
    int dprintf(int, const char * , ...) __attribute__((__format__ (__printf__, 2, 3))) __attribute__((availability(macosx,introduced=10.7)));
    int vdprintf(int, const char * , va_list) __attribute__((__format__ (__printf__, 2, 0))) __attribute__((availability(macosx,introduced=10.7)));
    ssize_t getdelim(char ** , size_t * , int, FILE * ) __attribute__((availability(macosx,introduced=10.7)));
    ssize_t getline(char ** , size_t * , FILE * ) __attribute__((availability(macosx,introduced=10.7)));
}







extern "C" {
    extern const int sys_nerr;
    extern const char *const sys_errlist[];
    
    int asprintf(char ** , const char * , ...) __attribute__((__format__ (__printf__, 2, 3)));
    char *ctermid_r(char *);
    char *fgetln(FILE *, size_t *);
    const char *fmtcheck(const char *, const char *);
    int fpurge(FILE *);
    void setbuffer(FILE *, char *, int);
    int setlinebuf(FILE *);
    int vasprintf(char ** , const char * , va_list) __attribute__((__format__ (__printf__, 2, 0)));
    FILE *zopen(const char *, const char *, int);
    
    
    
    
    
    FILE *funopen(const void *,
                  int (*)(void *, char *, int),
                  int (*)(void *, const char *, int),
                  fpos_t (*)(void *, fpos_t, int),
                  int (*)(void *));
}

struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    printf("Block.\n");}

static struct __main_block_desc_0 {
    size_t reserved;
    size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main()
{
    void (*blk)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA);
    ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
    return 0;
    
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
一经clang变换,原本只有8行的代码变成了500多行。
精简一下大概转换后的代码如下:
struct __block_impl {
    void *isa;
    int Flags;
    int Reserved;
    void *FuncPtr;
};

struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    printf("Block.\n");}

static struct __main_block_desc_0 {
    size_t reserved;
    size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main()
{
    void (*blk)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA);
    ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
    return 0;
    
}
来看看转换后的main()函数:

int main()
{
   void (*blk)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA);
    ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
   return 0;
    
}

blk在这里变成了一个指针,指向结构体 __main_block_impl_0,结构体 __main_block_impl_0初始化后被取地址强制转换成函数指针--void(*)()。__block_impl是一个公共实现(学过c语言的同学都知道,__main_block_impl_0的这种写法表示其可以被类型强转为__block_impl类型)
struct __block_impl {
   void *isa;
   int Flags;
   int Reserved;
   void *FuncPtr;
};
isa指针说明block可以成为一个objc 对象。

__main_block_impl_0的意思是main函数中的第0个block的implementation(命名:所属函数名main+block+implementation的缩写imply+block在所属函数中出现的顺序0),这个就是这个block的主体了。


在block中改写-静态局部变量-静态全局变量-全局变量-的值

int global_val = 1;
static int static_global_val = 2;

int main()
{
    static int static_val = 3;
    
    void (^blk)(void) = ^{
        global_val *=2;
        static_global_val *=3;
        static_val *=4;
    };
    return 0;
}
clang 变换后:
struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};


int global_val = 1;
static int static_global_val = 2;


struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int *static_val;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_static_val, int flags=0) : static_val(_static_val) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int *static_val = __cself->static_val; // bound by copy

        global_val *=2;
        static_global_val *=3;
        (*static_val) *=4;
    }

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main()
{
    static int static_val = 3;

    void (*blk)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &static_val);
    return 0;
}

加__block的变量

int main()
{
    __block int val_block = 3;
    
    void (^blk)(void) = ^{
        val_block *=4;
    };
    
    blk();
    
    return 0;
}

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

struct __Block_byref_val_block_0 {
  void *__isa;
__Block_byref_val_block_0 *__forwarding;
 int __flags;
 int __size;
 int val_block;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_val_block_0 *val_block; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_val_block_0 *_val_block, int flags=0) : val_block(_val_block->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_val_block_0 *val_block = __cself->val_block; // bound by ref

        (val_block->__forwarding->val_block) *=4;
    }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->val_block, (void*)src->val_block, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->val_block, 8/*BLOCK_FIELD_IS_BYREF*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main()
{
    __attribute__((__blocks__(byref))) __Block_byref_val_block_0 val_block = {(void*)0,(__Block_byref_val_block_0 *)&val_block, 0, sizeof(__Block_byref_val_block_0), 3};

    void (*blk)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_val_block_0 *)&val_block, 570425344);

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

    return 0;
}

就加了个__block,代码量马上剧增。令人惊讶的是加了__block的变量变成了一个结构体__Block_byref_val_0的实例.





你可能感兴趣的:(Objective-C,block,Clang)