On Thu, Sep 3, 2009 at 10:31 PM, David Leimbach <leim...@gmail.com> wrote:

>
>
> On Thu, Sep 3, 2009 at 9:44 PM, erik quanstrom <quans...@quanstro.net>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), <uninitialized>,
        __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
>>
>>
>

Reply via email to