Escape Analysis & Owner Escape Analysis
Richard Andrew Cattermole (Rikki)
richard at cattermole.co.nz
Sat Aug 24 12:20:13 UTC 2024
As a follow-up to the recent DIP1000 meeting where it was agreed
to start compiling a list of its failings and that inference is
important to such a design, I am also posting my proposal for a
complete replacement.
To those who have tried DIP1000 and then dumped it, I am
interested to know how you find the owner escape analysis of this
proposal in terms of being restrictiveness.
Please evaluate it, so I can know if there is a pattern that
needs resolving (if possible).
Latest:
https://gist.github.com/rikkimax/0c1de705bf6d9dbc1869d60baee0fa81
Current:
https://gist.github.com/rikkimax/0c1de705bf6d9dbc1869d60baee0fa81/c369cb4e9416298c6cf348915205959ee272a5f8
This proposal is an attempted potential replacement for both
DIP1000 and @live.
It is in recognition that we may not be able to get DIP1000 and
@live fully functional in making memory that is borrowed from
owners tracked within ``@safe`` code.
To do this, an escape set is described per parameter to describe
the relationship of an input to its output.
An output is one that is tied to one or more inputs, and an input
is any pointer that is stored in some place.
I do want to emphasize at this point that the escape set should
be more or less be perfect in terms of inference due to inference
as being a side effect of the verification. Rather than a
separate process.
Unless you go virtual, or lack a body the need to annotate should
be minimal.
A nice side effect of this, is that the compiler will be able to
promote memory to the stack without you annotating ``scope``.
Escape analysis provides guarantees to its caller on the
relationship to outputs for each function parameter. It is
cross-scope aware.
Owner escape analysis provides guarantees to the callee that the
inputs for each output will remain valid for the life of the
output value.
They are complimentary of each other, enabling each to be simpler.
Here is a reference counted type example, although this can
equally apply to any other pointer type:
```d
struct RC {
int* borrow() @escapevia(return);
}
RC first(/* @escapevia(return) */ RC input) {
int* borrowed1 = input.borrow();
// input is an owner, and therefore protected due to the
borrow borrowed1
input = RC.init; // Error
int* borrowed2 = second(borrowed1);
// borrowed1 is an owner, and therefore protected due to the
borrow borrowed2
borrowed1 = null; // Error
return input;
}
int* second(/* @escapevia(return) */ int* second) {
writeln(*second);
return second;
}
```
How it interacts with const:
```d
struct S {
int field;
@safe:
bool isNull() const {
return false;
}
void makeNull() {
}
}
S s;
int* field = &s.field;
writeln(s.isNull); // ok
s.makeNull(); // Error: Variable `s` has a borrow and may not be
mutated by calling `makeNull`.
```
This also works when not the this pointer, but instead is a
function parameter by-ref:
```d
void func(ref const S s) {
s = S(2); // Error: cannot modify `const` expression `s`
}
```
More information about the dip.ideas
mailing list