On Thu, Sep 3, 2009 at 10:31 PM, David Leimbach wrote: > > > On Thu, Sep 3, 2009 at 9:44 PM, erik quanstrom wrote: > >> > > that sucker is on the stack. by-by no-execute stack. >> > > how does it get to the stack? is it just copied from >> > > the text segment or is it compiled at run time? >> > > >> > >> > I don't think I posted the whole code, so that's my bad. The X was on >> the >> > stack to begin with as the first X was an automatic variable in a >> function. >> > I'd be a little surprised to find an automatic variable in the text >> > segment, but perhaps that's just my not remembering things properly. >> > (didn't mean that tongue in cheek, I don't think about that stuff much >> > these days, as I've spent the last year or so doing Erlang and Haskell.) >> >> it is the block itself that apple claims is on the stacp >> (your grand centeral reference, p. 38). and i wonder >> how it gets there. is it just copied from the text segment? >> that seems kind of pointless. why not just execute it >> from the text segment? or is it modified (compiled?) >> at run time? >> > > Right, my understanding is that blocks live on the stack, however it > appears that they get copied to a particular queue before being run, either > explicitly or implicitly depending on how it gets submitted. If you use > dispatch_after, it gets copied and released automatically after a certain > amount of time. > > The whole thing is very "eventy". > > Some of the documentation is not terribly explicit about how things get > copied if they do at all. Example is the dispatch_async call, which behaves > based on the queue to which it is submitted, but whether or not a copy > occurs is not mentioned. > > This document goes into more detail: > http://clang.llvm.org/docs/BlockImplementation.txt > > "Block literals may occur within functions where the structure is created > in stack local memory. They may also appear as initialization expressions > for Block variables of global or static local variables. > > When a Block literal expression is evaluated the stack based structure is initialized as follows: > > 1) static descriptor structure is declared and initialized as follows: > 1a) the invoke function pointer is set to a function that takes the Block structure as its first argument and the rest of the arguments (if any) to the Block and executes the Block compound statement. > 1b) the size field is set to the size of the following Block literal structure. > 1c) the copy_helper and dispose_helper function pointers are set to respective helper functions if they are required by the Block literal > 2) a stack (or global) Block literal data structure is created and initialized as follows: > 2a) the isa field is set to the address of the external _NSConcreteStackBlock, which is a block of uninitialized memory supplied in libSystem, or _NSConcreteGlobalBlock if this is a static or file level block literal. > 2) The flags field is set to zero unless there are variables imported into the block that need helper functions for program level Block_copy() and Block_release() operations, in which case the (1<<25) flags bit is set." > > I'm still left feeling somewhat not understanding how it all works :-) > > > Actually, reading on a bit more they deal with the "variable capture" talking about const copies. Automatic storage variables not marked with __block are imported as const copies. The simplest example is that of importing a variable of type int. int x = 10; void (^vv)(void) = ^{ printf("x is %d\n", x); } x = 11; vv(); would be compiled 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) }; and struct __block_literal_2 __block_literal_2 = { &_NSConcreteStackBlock, (1<<29), , __block_invoke_2, &__block_descriptor_2, x }; In summary, scalars, structures, unions, and function pointers are generally imported as const copies with no need for helper functions. > >> - erik >> >> >