Escape analysis

Steven Schveighoffer schveiguy at yahoo.com
Mon Oct 27 13:26:55 PDT 2008


"Walter Bright" wrote
> The delegate closure issue is part of a wider issue - escape analysis. A 
> reference is said to 'escape' a scope if it, well, leaves that scope. 
> Here's a trivial example:
>
> int* foo() { int i; return &i; }
>
> The reference to i escapes the scope of i, thus courting disaster. Another 
> form of escaping:
>
> int* p;
> void bar(int* x) { p = x; }
>
> which is, on the surface, legitimate, but fails for:
>
> void abc(int j)
> {
>     bar(&j);
> }
>
> This kind of problem is currently undetectable by the compiler.
>
> The first step is, are function parameters considered to be escaping by 
> default or not by default? I.e.:
>
> void bar(noscope int* p);    // p escapes
> void bar(scope int* p);      // p does not escape
> void bar(int* p);            // what should be the default?
>
> What should be the default? The functional programmer would probably 
> choose scope as the default, and the OOP programmer noscope.
>
> (The issue with delegates is we need the dynamic closure only if the 
> delegate 'escapes'.)

I think the default should be no escape.  This should cover 90% of cases, 
and does not have an 'allocate by default' policy.

But I think whether a variable escapes or not cannot really be determined by 
the function accepting the variable, since the function doesn't know where 
the variable comes from.  An example:

void bar(int *x, ref int *y) { y = x;}

How do you know that y is not defined in the same scope or a sub-scope of 
the scope of x?  If the compiler sees:

void bar(noscope int *x, scope ref int *y)

It's going to assume that x will always escape, and probably allocate a 
closure so it can call bar.  Which might not be the right decision.

I think that without a full graph analysis of what escapes to where, it is 
going to be impossible to make this correct for the compiler to use, and 
that might be too much for the compiler to deal with.  I'd rather just have 
the compiler assume scope unless told otherwise (at the point of use, not in 
the function signature).

For instance:

void bar(int *x, ref int *y) { y = x;}

void abc(int x, ref int *y)
{
   bar(noscope &x, y);
}

void abc2()
{
   int x;
   int *y;
   bar(&x, y);
}

tells the compiler to allocate a closure for abc, because x might escape. 
But does not allocate a closure for abc2, because there are no escapes 
indicated by the developer.

-Steve 





More information about the Digitalmars-d mailing list