Block 实现中的 flags
Contents
https://clang.llvm.org/docs/Block-ABI-Apple.html llvm 对 flags 文档的描述不完整,最新的代码已经扩展到了 1 << 31
enum {
// Set to true on blocks that have captures (and thus are not true
// global blocks) but are known not to escape for various other
// reasons. For backward compatiblity with old runtimes, whenever
// BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a
// non-escaping block returns the original block and releasing such a
// block is a no-op, which is exactly how global blocks are handled.
BLOCK_IS_NOESCAPE = (1 << 23),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
BLOCK_HAS_SIGNATURE = (1 << 30),
};
翻看 block 的实现可以看到
// Values for Block_layout->flags to describe block objects
enum {
BLOCK_DEALLOCATING = (0x0001), // runtime
BLOCK_REFCOUNT_MASK = (0xfffe), // runtime
BLOCK_NEEDS_FREE = (1 << 24), // runtime
BLOCK_HAS_COPY_DISPOSE = (1 << 25), // compiler
BLOCK_HAS_CTOR = (1 << 26), // compiler: helpers have C++ code
BLOCK_IS_GC = (1 << 27), // runtime
BLOCK_IS_GLOBAL = (1 << 28), // compiler
BLOCK_USE_STRET = (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE
BLOCK_HAS_SIGNATURE = (1 << 30), // compiler
BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31) // compiler
};
代码随处可见的下列汇编就是将 (1<<29)|(1<<30) 赋值
MOV W8, #0xC2000000
Block 的类型
众所周知有 global、stack、malloc 类型,查看源代码发现不止这三个
Foundation 会在合适的时机把这些变量填充为正确的值
void * _NSConcreteStackBlock[32] = { 0 };
void * _NSConcreteMallocBlock[32] = { 0 };
void * _NSConcreteAutoBlock[32] = { 0 };
void * _NSConcreteFinalizingBlock[32] = { 0 };
void * _NSConcreteGlobalBlock[32] = { 0 };
void * _NSConcreteWeakBlockVariable[32] = { 0 };
global 只要不截获自动变量,都是 global 的
(一)static
static Block block = ^(int a) {
return 0;
}; 这是 global
int i = 0;
static Block block = ^(int a) {
return i;
}; 这是编译不过
(二)文件级别,就是全局的
block = ^(int a) {
return 0;
}; 这是 global
int i = 0;
block = ^(int a) {
return i;
}; 这是 malloc 的
__weak Block block;
int i = 0;
block = ^(int a) {
return i;
}; 这是 stack 的
所以只要是被 __weak 修饰的都是 stack 的。
malloc 只要是截获了自动变量的,都是的 malloc 的。
malloc 的情况下,只要给加一个 __weak 修饰,就是 stack 的。