On Fri, 04 Sep 2009 00:44:35 EDT erik quanstrom <[email protected]> wrote:
> > > that sucker is on the stack. by-by no-execute stack.
I don't think so. See below.
> > > 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?
[Note: I am simply guessing and have no idea how they
actually do this but this model seems workable]
Consider this example:
int foo(int a) {
__block int b = 0;
int (^g()) = ^{ return a + ++b; }
...
return g() + g();
}
My guess is the above will be translated to something like this:
struct anon1 {
int (*f)(struct anon1*);
const int a;
int *const bp;
};
int anon1_f(struct anon1* x) {
return x->a + ++(*x->bp);
}
int foo(int a) {
int *bp = malloc(sizeof *bp); // not quite. see the correction below
*bp = 0;
struct anon1 _anon = { &anon1_f, a, &b };
struct anon1* g = &_anon;
...
return g->f(&_anon) + g->f(&_anon);
}
As you can see, _anon will disappear when foo() is exited.
But if you were to Block_copy() _anon, it will be allocated
on the heap and a ptr to it returned. Now you do have
everything needed to call this anon function even after
returning from foo(). &_anon can also be passed to another
thread etc. with no problem.
Most likely __block variables are allocated on the heap and
ref counted. Ref count is decremented on exit from the
lexical scope where a __block var is defined. Block_copy()
increments refcount of every __block var referenced by the
block, Block_release() decrements it.
So this is basically a function closure. They seem to have
very carefully navigated around C's semantic sand bars.