Escape analysis (full scope analysis proposal)

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sun Nov 2 16:04:37 PST 2008


Michel Fortin wrote:
> On 2008-11-02 10:12:46 -0500, Andrei Alexandrescu 
> <SeeWebsiteForEmail at erdani.org> said:
> 
>> It looks like things will move that way. Bartosz, Walter and I talked 
>> a lot yesterday about it - a lot of crazy things were on the table! 
>> The next step is to make this a reference, which is highly related to 
>> escape analysis. At the risk of anticipating a bit an unfinalized 
>> design, here's what's on the table:
>>
>> * Continue an "anything goes" policy for *explicit* pointers, i.e. 
>> those written explicitly by user code with stars and stuff.
> 
> That's a little disapointing. I was hoping for something to fix all 
> holes. I know it isn't easy to design and implement, but once done I 
> firmly believe it would have the potential to completely eliminate the 
> need for explicit memory allocation. For the programmer, it's a good 
> trade: less worrying about what needs to be dynamically allocated and 
> better documented function signatures.
> 
> Perhaps that would be too much of a departure from C and C++ though.

That's only the half of it. If you want to take a look at a C-like 
language that is safe, you may want to look at Cyclone. The reality is 
that making things 100% safe are going to require more or less the moral 
equivalent of Cyclone's limitations and demands from its user. I think 
Dan Grossman has done an excellent job making things "as tight as 
possible but not tighter", so Cyclone is a great yardstick to measure 
D's tradeoffs against.

>> * Disallow pointers in SafeD.
> 
> Again a consequence of not having a full scoping solution.

A "full scoping solution" would impose demands on you that you'd be the 
first to dislike.

> Couldn't you allow pointers in SafeD, while disallowing taking the 
> address of local variables? This would limit pointers to heap-allocated 
> variables. And disallow pointer arithmetic too.

I think pointers can be allowed in SafeD under certain restrictions 
starting with the ones you mention. We best start from the safe end.

>> * Make all ref parameters scoped by default. There will be impossible 
>> for a function to escape the address of a ref parameter without a 
>> cast. I haven't proved it to myself yet, but I believe that if 
>> pointers are not used and with the amendments below regarding arrays 
>> and delegates, this makes things entirely safe. In Walter's words, "it 
>> buttons things pretty tight".
> 
> If this means you can't implement a swap function for this struct, then 
> I think you're right that it's safe:
> 
>     struct A
>     {
>         ref A a;
>     }
> 
>     void swap(ref A a0, ref A a1);
> 
> On the other side, if you can implement the swap function, then calling 
> it is unsafe since you can rebind a reference to another without being 
> able to check that their scopes are compatible.

Swap will work fine because ref is not a type constructor. Struct A is 
in error. In fact ref not being a type constructor is much of the beauty 
of it all.

> So basically, references must always be initialized at construction and 
> should be non-rebindable, just like in C++. (Hum, and I should mention I 
> don't like too much references in C++.)

No, C++ references are "almost" type constructors. Also note that 
rvalues won't bind to any kind of references in D. (More on that later.)

>> * Make this a reference so that it obeys what references obey.
> 
> Ah, so that's why Walter wanted to change that suddenly. This is a good 
> thing by itself, even without correct scoping.

Yah, in fact it's pretty amazing it seems to work out so well. We gain a 
huge guarantee without changing much in the language.

>> * If people want to implement e.g. linked lists, they should do it 
>> with classes. Implementing them with structs will require casts to 
>> obtain and escape &this. That also means they'd be using pointers, so 
>> anything goes - pointers are not restricted from escaping.
>>
>> * There are two cases in which things escape without the user 
>> explicitly using pointers: delegates and dynamic arrays initialized 
>> from stack-allocated arrays.
>>
>> * For delegates require the scope keyword in the signature of the 
>> callee. A scoped delegate cannot be stored, only called or passed down 
>> to another function that in turn takes a scoped delegate. This makes 
>> scope delegates entirely safe. Non-scoped delegates use dynamic 
>> allocation.
> 
> Again, I'd say that if you can implement a swap function with those 
> scope delegates, it's unsafe. Case in point:
> 
>     void f1(ref scope void delegate() arg)
>     {
>         int i;
>         scope void f2()
>         {
>             ++i;
>         }
> 
>         scope void delegate() inner = &f2;
>         swap(arg, inner); // this should be an error.
>         arg = inner; // this too should be an error.
>     }
> 
> If you can't rebind a the value of a scope delegate pointer, then all is 
> fine.

Indeed, rebinding would be disallowed.

>> * We don't have an idea for dynamic arrays initialized from 
>> stack-allocated arrays.
> 
> Either disallow it, either keep it as unsafe as pointers (bad for SafeD 
> I expect), or implement a complete scope-checking system (if you do it 
> for arrays, you'll have done it for pointers too). You don't have much 
> choice there, as arrays are pretty much the same thing as pointers.

Exactly. Essentially array are as "bad" as structs containing pointers.

>> Thoughts? Ideas?
> 
> I'm under the impression that scope classes could be dangerous in this 
> system: an object reference is not necessarly on the heap.

I think a fair move to do is deal away with scope classes. We can still 
allow them via systems-level tricks, but not with an innocuous construct 
that's in fact a weapon of mass destruction.

> Personally, I'd have liked to have a language where you can be 
> completely scope safe, where you could document interfaces so they know 
> the scope they're evolving in. This concept of something in between is a 
> nice attempt at a compromize, but I find it somewhat limitting.

I agree. Again, something like this was on the table:

void wyda(scope T* a, scope U* b)
         if (scope(a) <= scope(b)
{
     a.field = b;
}

I think it's not hard to appreciate the toll this kind of user-written 
function summary exacts on the user of the language.


Andrei



More information about the Digitalmars-d mailing list