On Borrow Checking
Richard (Rikki) Andrew Cattermole
richard at cattermole.co.nz
Thu May 1 02:28:38 UTC 2025
On 01/05/2025 10:53 AM, Walter Bright wrote:
> On 4/29/2025 8:25 PM, Richard (Rikki) Andrew Cattermole wrote:
>> 1. Ban all pointers. System handles and with that coroutines/fibers
>> are all @trusted and @system so it doesn't effect them. Anything else
>> should be using the GC and therefore unaffected by this restriction.
>
> Memory unsafety happens when there's a pointer into the reference
> counted object that is a direct pointer.
Right, if you don't have the escape analysis to protect the owner,
banning all pointers surrounding the RC type solves it inherently.
I don't like the idea of banning all pointers, but it does solve the
problem for system handles since they are not regular code. Which is the
purpose of having RC in the language (for my motivation).
>> 2. Let the backend handle optimizations. Reference counting primitives
>> are improving (at least in LLVM). Worst case scenario, we have the
>> exact same performance as we do now, but with a better user experience.
>
> Performance problems come from:
>
> 1. using a mutex (not an issue for thread local data)
>
> 2. needing an exception handler for the decrement
>
> 3. increment
>
> 4. decrement-test-free
Why are you treating these as new costs? I don't understand.
They are already being paid for with copy constructors and destructors.
But if you are want to remove it, it can be solved.
My plan was to solve this with my DFA framework.
However, for a dedicated solution:
1. Put the add call into the called function as part of the calling
convention (extremely important).
2. If a variable declaration has a RC type, flag the function
declaration as containing RC during semantic 3.
3. If a function contains RC, call optimization DFA iff optimizations
are turned on (speed is not a concern if optimizations are turned off).
4. Use a stack, a nice simple one.
4.1. When you see an add, add the call to the stack.
4.2. When you see end of scope, remove all add's in stack corresponding
to that stack.
4.2.1. If a removed add does not have the flag that it is required,
disable it and its corresponding sub.
4.3. If mutation event occurs on a variable, find its last add in stack,
flag it as requried.
4.3.1. A mutation event is anything that could mutate the variable, i.e.
ref, out, taking a pointer, assignment.
5. Do not codegen any expression that has been marked as disabled.
You do not need control flow block handling for this.
If it cannot disable calls, its because they are needed.
```d
void func(RC input) {
input.add; // elidable
scope(exit)
input.sub; // elidable
if (condition) {
input.sub;
input = RC(...);
input.add;
}
}
```
More information about the Digitalmars-d
mailing list