Escaping the Tyranny of the GC: std.rcstring, first blood
Dmitry Olshansky via Digitalmars-d
digitalmars-d at puremagic.com
Sun Sep 28 03:40:23 PDT 2014
28-Sep-2014 00:16, Andrei Alexandrescu пишет:
> On 9/27/14, 12:50 PM, Dmitry Olshansky wrote:
>> 27-Sep-2014 23:14, Andrei Alexandrescu пишет:
>>> On 9/27/14, 2:38 AM, Dmitry Olshansky wrote:
>>>>
>>>> Okay it serves no good for me to make these tiny comments while on the
>>>> go.
>>>>
>>>> As usual, structs are value types, so this feature can be mis-used, no
>>>> two thoughts abouts it. It may need a bit of improvement in
>>>> user-friendliness, compiler may help there by auto-detecting common
>>>> misuse.
>>>
>>> I still don't understand what "this feature" is after reading your long
>>> post twice.
Must be my fault, I'll try once again.
>>>
>>> So structs are still value types and you replace postblit/destroy with
>>> calls to opInc/opDec? That's it? How does this enable anything more
>>> interesting than ctors/dtors?
>>>
>>
>> Compiler is aware that opInc and opDec are indeed ref-countinng ops,
>> meaning that opInc + opDec = no op. I claim that this is enough to get
>> "ARC" going.
>
> You give marginal details but still don't describe the thing. When are
> they called and what do they have that ctors/dtors/postblit don't?
The key point is that the change is small, that's why (maybe) it's hard
to grasp. The whole thing is a bit of lowering and a "hint" to the
compiler. It reuses the same mechanism that structs already have.
Okay a few examples of lowering to get things going:
http://dpaste.dzfl.pl/3722d9d70937
(note I think there could be better lowerings and simpler set of
primitives to bootstrap ARC-ed type)
Now why would we need this trivial lowering?
Typical postblit can be anything unless the compiler has full source
code, dtor can be anything as well.
With opInc/opDec compiler generates postblit/dtor on his own, in doing
so it decorates user-defined dtor that actually clears resources.
What being in control gives to the compiler:
1. Compiler always has the source of generated parts, so they can be
inlined (and should be)
2. Can do typical algebra optimization on opInc/opDec, no matter what's
inside opInc and opDec (this is a contract between programmer and compiler).
e.g opInc(10) followed by OpDec(1) is opInc(9)
3. Also opInc and opDec do not alter object in any capacity, nor are
they affected by any method calls on this object (another contract)
4. 1 + 2 = win, as by inlining postblits/dtors we expose opInc/opDecs to
the optimizer pass which the would fold them using basic algebra
optimizations.
Motivating example:
struct RC(T) { ... } //implemented with or without proposed feature
void foo(RC!int arg); // no source available, sorry;)
void bar(RC!int my)
{
foo(my);
writeln("Bar: ", *my);
}
which is the same as
{
{
auto __tmp = my; // a postblit
foo(__tmp);
}//dtor
writeln("Bar: ", *my);
}
And assuming the same names for inc/dec of count and no exceptions, can
be simplified back to:
{
{
auto __tmp = my;
my.opInc(1); // or __tmp.opInc() it's the same count
foo(__tmp);
if(my.opDec(1)) my.__dtor();
}
writeln("Bar: ", *my);
}
Ideally with assumptions I stated above will look like this:
{
{
auto __tmp = my;
foo(__tmp);
if(my.opDec(0)) my.__dtor();
}
writeln("Bar: ", *my);
}
Now here if compiler can optimize ref-count operations completely on his
own without assumptions stated above then we are done and no special
opInc/opDec required.
I bet my hat it can't for the simple reason that all bets are off if any
of the following is happening:
1. No source available thus e.g. postblit is opaque call
2. Not "everything" in between opInc/opDec can be inlined impairing
optimizer (since 'my' is passed to foo, it may be modified)
I might be wrong though - Walter?
>
> FWIW the language always "understands" when to elide postblit/dtor calls.
Yes, which immediately gives us part of ARC advantages such as NRVO
elides ref-count bump. The other part comes from batching up multiple
incs/decs to one call and eliminating redundant pairs.
I might be wrong but RCObject proposal is harder to construct then this
"feather-weight ARC" as it would have to "force" the same lifetime
management as we have for structs on some class instances that never had
it before!
That being said I think it's valuable to have RCObject and exceptions
being ref-counted.
--
Dmitry Olshansky
More information about the Digitalmars-d
mailing list