Escape Analysis & Owner Escape Analysis
Richard (Rikki) Andrew Cattermole
richard at cattermole.co.nz
Thu Sep 5 10:28:45 UTC 2024
On 05/09/2024 9:53 PM, IchorDev wrote:
> On Wednesday, 4 September 2024 at 03:02:10 UTC, Richard (Rikki) Andrew
> Cattermole wrote:
>> owner escape analysis only kicks in and forces effectively const on
>> the owner if:
>>
>> 1. You take a pointer to stack memory
>> 2. You receive memory that has a strong relationship (perhaps done
>> explicitly for reference counting!)
>> 3. You take a pointer to a field of struct/class/union
>>
>> […]
>>
>> In a way its a hole in the design, but an intentional one as it makes
>> for a very good user experience and doesn't really have a lot of down
>> sides.
>>
>> I was going to fill in that hole, but ``@system`` variables covers it
>> enough that I kinda just went meh.
>
> Wait, so how would one force owner escape analysis to be enabled for
> manually heap-allocated memory? This DIP is meant to replace @live,
> after all.
You need to establish a strong relationship either to a variable, or
from it.
For a method call add ``scope`` on the this pointer:
```d
struct RC {
int* borrow() scope;
}
```
For variable declaration:
```d
scope int* owner = new int;
```
Take a pointer:
```d
struct Top {
int field;
}
Top top;
int* borrow = &top.field;
```
I have not added meaning for ``scope`` on a field, although I can see
that this might be nice to add. I'm not sure if that is needed. Is this
a hole for you?
Are you expecting a type qualifier? It is not needed for this.
```d
struct Thing {
int* ptr;
}
void caller() {
scope Thing owner;
called(owner); // Error: owner would escape to an unknown location
}
int* global;
void called(@escape(__unknown) /*weak*/ Thing thing) {
global = thing.ptr;
}
```
This is a rather clever aspect of weak vs strong relationships, a weak
relationship tells the analysis about how memory is moving around. You
do not need to understand the full graph, as long you understand your
own function body and those that you call function signatures.
In general I strongly suggest wrapping raw memory in an RC owner, this
allows you move it around safely, and then borrow from it (kicking off
owner escape analysis).
```d
struct Wrapper {
private @system {
int* ptr;
}
int* borrow() @escape(return) scope @trusted {
return ptr;
}
}
Wrapper acquire() {
Wrapper wrapper = ...;
{
int* borrowed = wrapper.borrow();
...
}
return wrapper;
}
```
I have a feeling that this won't be answering your question, is there
something I'm for whatever reason not understanding about it?
>>> - `@escape` is the opposite of `@escape()`, which could be confusing
>>
>> Originally I was going to make this to mean 'inferred', but it's
>> better if everything gets inferred by default.
>>
>> It needs to mean something, so got an alternative?
>
> Maybe add a special case for something like `@escape(false)`?
The question is for what ``@escape()`` would do. Which Dennis has not
counter proposal for.
More information about the dip.ideas
mailing list