October 10, 2013
On 6/25/2013 8:08 PM, Steven Schveighoffer wrote:
> On Jun 25, 2013, at 11:04 PM, Walter Bright wrote:
>
>> On 6/25/2013 6:31 PM, Michel Fortin wrote:
>>> And finally, there's nothing unsafe with autorelease pools as long as you don't keep an unretained reference to an autoreleased object when the pool drains.
>> Well, that's exactly the issue - an escaping reference.
>>
> Read the next sentence after your quote though:
>
> "Making sure you have no unretained reference is ARC's job, so with ARC it should not be no problem."
>
> So with ARC, it's not unsafe.  I think that was the ultimate point.

Yes, I read the next sentence. What it means to me is that autorelease pools add nothing when ARC is implemented - no optimizations, either. Either that or I don't understand how ARC figures out that there are no escaping references without doing things like runtime checks.

October 10, 2013
Steven Schveighoffer wrote:

On Jun 26, 2013, at 12:10 AM, Walter Bright wrote:

>
> On 6/25/2013 8:08 PM, Steven Schveighoffer wrote:
>> On Jun 25, 2013, at 11:04 PM, Walter Bright wrote:
>>
>>> On 6/25/2013 6:31 PM, Michel Fortin wrote:
>>>> And finally, there's nothing unsafe with autorelease pools as long as you don't keep an unretained reference to an autoreleased object when the pool drains.
>>> Well, that's exactly the issue - an escaping reference.
>>>
>> Read the next sentence after your quote though:
>>
>> "Making sure you have no unretained reference is ARC's job, so with ARC it should not be no problem."
>>
>> So with ARC, it's not unsafe.  I think that was the ultimate point.
>
> Yes, I read the next sentence. What it means to me is that autorelease pools add nothing when ARC is implemented - no optimizations, either. Either that or I don't understand how ARC figures out that there are no escaping references without doing things like runtime checks.

OK, it sounded like you were saying still that Objective C with ARC didn't have memory safety.

I'm no longer arguing about autorelease, I defer to Michel on that.  I clearly didn't understand that autorelease doesn't provide any benefits for ARC, it's just there for compatibility.

-Steve
October 10, 2013
On 6/25/2013 9:13 PM, Steven Schveighoffer wrote:
> OK, it sounded like you were saying still that Objective C with ARC didn't have memory safety.

My initial first pass read of:

http://clang.llvm.org/docs/AutomaticReferenceCounting.html

indicates that ARC does not guarantee memory safety. There are a number of "undefined" behaviors when the O-C programmer does not follow the rules.
October 10, 2013
On 6/25/2013 6:09 PM, Michel Fortin wrote:
> ## Some general comments
>
> While its a start, this is hardly enough for Objective-C. Mostly for legacy reasons, most Objective-C methods return autoreleased objects (deferred release using an autorelease pool) based on a naming convention. Also, Objective-C objects can't be allocated from the D heap, so to avoid cycles we need weak pointers. More on Objective-C later.
>
> While it's good that a direct call to AddRef/Release is forbidden in @safe code, I think it should be forbidden in @system code too. The reason is that if the compiler is inserting calls to these automatically and you're also adding your own explicitly in the same function, it becomes practically impossible to reason about the reference counts, short of looking at the assembly. Instead, I think you should create a @noarc attribute for functions: it'll prevent the compiler for inserting any of those calls so it becomes the responsibility of the author to make those calls (which are then allowed). @noarc would be incompatible with @safe, obviously.

It's a good point, but adding such an attribute to the function may be too coarse, for one, and may cause composition problems, for another. Maybe just disallowing it altogether is the best solution.

>
> Finally, that's a nitpick but I wish you'd use function names that fit D better, such as opRetain and opRelease. Then you can add a "final void opRetain() { AddRef(); }" function to the IUnknown COM interface and we could do the same for Objective-C.

Makes sense.

>
> ## Objective-C autoreleased objects
>
> Objective-C is a special case. In Objective-C we need to know whether the returned object of a function is already retained or if it is deferred released (autoreleased). This is easily deducted from the naming convention. Occasionally, we might need to create autorelease pools too, but that can probably stay @system.
>
> (Note: all this idea of autoreleased objects might sound silly, but it was a great help before ARC, and Objective-C ARC has to be compatible with legacy code so it conforms to those conventions.)
>
> You can easily implement ARC for COM using an implementation of ARC for Objective-C, the reverse is not true because COM does not have this (old but still needed) concept of autorelease pools and deferred release where you need to know at each function boundary whether returned values (including those returned by pointer arguments) whether the object is expected to be retained or not.
>
> If I were you Walter, I would just not care about Objective-C idioms while implementing this feature at first. It'll have to be special cased anyway. Here's how I expect that'll be done:

From reading over that clang document, O-C arc is far more complex than I'd anticipated. I think it is way beyond what we'd want in regular D. It also comes with all kinds of pointer and function annotations - something I strongly want to avoid.

>
> What will need to be done later when adding Objective-C support is to add an internal "autoreleasedReturn" flag to a function that'll make codegen call "autorelease" in the callee when returning an object and "retain" in the caller where it receives an object from a function with that flag. Also, the same flag and behaviour is needed for out parameters (to mimick those cases where an object is returned by pointer). That flag will then be set automatically internally depending on the function name (only for Objective-C member functions), and it should be possible to override it explicitly with an attribute or a pragma of some sort. This is what Clang is doing, and we must match that to allow things to work.

I agree that this complexity should only be in O-C code.

>
> Checking for null is redundant in the Objective-C case: that check is done by the runtime. That's of minor importance, but it might impact performance and should probably special-cased in this case.
>
> ## Optimizations
>
> With Apple's implementation of reference counting (using global hash tables protected by spin locks), it is more efficient to update many counters in one operation. The codegen for Objective-C ARC upon assignement to a variable calls "objc_storeStrong(id *object, id value)", incrementing and decrementing the two counters presumably in one operation (as well as replacing the content of the variable pointed by the first argument with the new value).
>
> Ideally, the codegen for Objective-C ARC in D would call the same functions so we have the same performance. This means that codegen should make a call "objc_retain" when first initializing a variable, "objc_storeStrong" when doing an assignment, and "objc_release" when destructing a variable.
>
> As for returning autoreleased objects, there are two functions to choose from depending on whether the object needs to be retained at the same time nor not. (In general, the object needs to be retained prior autoreleasing if it comes from a variable not part of the function's stack frame.)
>
> Here's Clang's documentation for how it implements ARC:
> http://clang.llvm.org/docs/AutomaticReferenceCounting.html
>
> ## Objective-C weak pointers
>
> Weak pointers are essential in order to break retain cycles in Objective-C where there is no GC. They are implemented with the same kind of function calls as strong pointers. Unfortunately, Apple's Objective-C implementation won't sit well with D the way it works now.
>
> Weak pointers are implemented in Objective-C by registering the address of the pointer with the runtime. This means that when a pointer is moved from one location to another, the need to be notified of that through a call to objc_moveWeak. This breaks one assumption of D that you can move memory at will without calling anything.
>
> While we could still implement a working weak pointer with a template struct, that struct would have to allocate a pointer on the heap (where it is guarantied to not move) so it can store the true weak pointer recognized by the runtime. I'm not sure that would be acceptable, but at least it would work.
>
> ## More on reference counting
>
> I feel like I should share some of my thoughts here about a broader use of reference counting in D.
>
> First, we don't have to assume the reference counter has to be part of the object. Apple implements reference counting using global hash tables where the key is the address. It works very well.
>
> If we added a hash table like this for all memory allocated from the GC, we'd just have to find the base address of any memory block to get to its reference counter. I know you were designing with only classes in mind, but I want to point out that it is possible to reference-count everything the GC allocates if we want to.

D would need manual, RC and GC to coexist peacefully.

>
> The downside is that every assignment to a pointer anywhere has to call a function. While this is some overhead, it is more predictable than overhead from a GC scan and would be preferred in some situation (games I guess). Another downside is you have an object retained by being present on the stack frame of a C function, it'd have to be explicitly retained from elsewhere.

Doesn't this make it impractical to mix vanilla C with D code? An important feature of D is this capability, without worrying about a "JNI" style interface. As for D switching to a full refcounted GC for everything, I'm very hesitant for such a step. For one thing, reading the clang spec on all the various pointer and function annotations necessary is very off-putting.


>
> As for pointers not pointing to GC memory, the generic addRef/release functions can ignore those pointers just like the GC ignores them today when it does its scan.
>
> Finally, cycles can still be reclaimed by having the GC scan for them. Those scans should be less frequent however since most of the memory can be reclaimed through reference counting.
>
>
>
October 10, 2013
Rainer Schuetze wrote:

On 25.06.2013 23:00, Walter Bright wrote:
> Updated incorporating Steven's suggestion, and some comments about
> shared/const/mutable/purity.
>
> -------------------------------------------------------------
>
>      Adding Reference Counting to D

Cool. I didn't expect this to be tackled so soon.

>
[...]
>
> 3. A ref counted object is inherently a reference type, not a value type.

As Michel also said, the reference count does not have to be in inside the object itself, so we might want to allow reference counting on other types aswell.

>
> 4. The compiler needs to know about ref counted types.

I imagine a few (constrained) templated functions for the different operations defined in the library could also do the job, though it might drown compilation speed. Also getting help from the optimizer to remove redundant calls will need some back doors.

>
>
> ==Proposal==
>
> If a class contains the following methods, in either itself or a base
> class, it is
> an RC class:
>
>
>      T AddRef();
>      T Release();

Is T typeof(this) here?

I don't think we should force linking this functionality with COM, the programmer can do this with a simple wrapper.

>
> An RC class is like a regular D class with these additional semantics:
>
> 1. In @safe code, casting (implicit or explicit) to a base class that
> does not
> have both AddRef() and Release() is an error.
>
> 2. Initialization of a class reference causes a call to AddRef().
>
> 3. Assignment to a class reference causes a call to AddRef() on the new
> value
> followed by a call to Release() on its original value.

It might be common knowledge, but I want to point out that the usual COM implementation (atomic increment/decrement and free when refcount goes down to 0) is not thread-safe for shared pointers. That means you either have to guard all reads and writes with a lock to make the full assignment atomic or have to implement reference counting very different (e.g. deferred reference counting).

>
> 4. Null checks are done before calling any AddRef() or Release().
>
> 5. Upon scope exit of all RC variables or temporaries, a call to
> Release() is performed,
> analogously to the destruction of struct variables and temporaries.
>
> 6. If a class or struct contains RC fields, calls to Release() for those
> fields will
> be added to the destructor, and a destructor will be created if one
> doesn't exist already.
>
> 7. If a closure is created that contains RC fields, either a compile
> time error will be
> generated or a destructor will be created for it.
>
> 8. Explicit calls to AddRef/Release will not be allowed in @safe code.
>
> 9. A call to AddRef() will be added to any argument passed as a parameter.
>
> 10. Function returns have an AddRef() already done to the return value.
>
> 11. The compiler can elide any AddRef()/Release() calls it can prove are
> redundant.
>
> 12. AddRef() is not called when passed as the implicit 'this' reference.
>

Isn't this unsafe if a member function is called through the last existing reference and this reference is then cleared during execution of this member function or from another thread?

> 13. Taking the address of, or passing by reference, any fields of an RC
> object
> is not allowed in @safe code. Passing by reference an RC field is allowed.

Please note that this includes slices to fixed size arrays.

>
> 14. RC objects will still be allocated on the GC heap - this means that
> a normal
> GC run will reap RC objects that are in a cycle, and RC objects will get
> automatically
> scanned for heap references with no additional action required by the user.
>
> 15. The class implementor will be responsible for deciding whether or
> not to support
> sharing. Casting to shared is already disallowed in @safe code, so this
> is only
> viable in system code.
>
> 16. RC objects cannot be const or immutable.

This is a bit of a downer. If the reference count is not within the object, this can be implemented.

>
> 17. Can RC objects be arguments to pure functions?
>
> ==Existing Code==
>
> D COM objects already have AddRef() and Release(). This proposal should
> not break
> that code, it'll just mean that there will be extra AddRef()/Release
> calls made.
> Calling AddRef()/Release() should never have been allowed in @safe code
> anyway.
>
> Any other existing uses of AddRef()/Release() will break.
>
> ==Arrays==
>
> Built-in arrays have no place to put a reference count. Ref counted
> arrays would hence
> become a library type, based on a ref counted class with overloaded
> operators for
> the array operations.
>
> ==Results==
>
> This is a very flexible approach, allowing for support of general RC
> objects, as well
> as specific support for COM objects and Objective-C ARC.
> AddRef()/Release()'s implementation
> is entirely up to the user or library writer.
>
> @safe code can be guaranteed to be memory safe, as long as
> AddRef()/Release() are correctly
> implemented.
>

I feel I'm hijacking this proposal, but the step to library defined read/write barriers seems pretty small. Make AddRef, Release and assignment free template functions, e.g.

void ptrConstruct(T,bool stackOrHeap)(T*adr, T p);
void ptrAssign(T,bool stackOrHeap)(T*adr, T p);
void ptrRelease(T,bool stackOrHeap)(T*adr);

and we are able to experiment with all kinds of sophisticated GC algorithms including RC. Eliding redundant addref/release pairs would need some extra support though, I read that LLVM does something like this, but I don't know how.



October 10, 2013
On 6/26/2013 12:19 AM, Rainer Schuetze wrote:
>
> As Michel also said, the reference count does not have to be in inside the object itself, so we might want to allow reference counting on other types aswell.

That opens the question of what is the point of other RC types? For example, C++ can throw any type - but it turns out that throwing anything but class types is largely pointless.

My proposal does not specify where the count actually is - the two functions can be arbitrarily implemented.

>
>>
>> 4. The compiler needs to know about ref counted types.
>
> I imagine a few (constrained) templated functions for the different operations defined in the library could also do the job, though it might drown compilation speed. Also getting help from the optimizer to remove redundant calls will need some back doors.

I don't see how this can be done without specific compiler knowledge in a memory safe way.

>
>>      T AddRef();
>>      T Release();
>
> Is T typeof(this) here?

T is not relevant to the proposal - it's up to the specific implementation of those functions.

>
> I don't think we should force linking this functionality with COM, the programmer can do this with a simple wrapper.

Yeah, that's Michel's suggestion, and it's a good one.

>
>>
>> An RC class is like a regular D class with these additional semantics:
>>
>> 1. In @safe code, casting (implicit or explicit) to a base class that
>> does not
>> have both AddRef() and Release() is an error.
>>
>> 2. Initialization of a class reference causes a call to AddRef().
>>
>> 3. Assignment to a class reference causes a call to AddRef() on the new
>> value
>> followed by a call to Release() on its original value.
>
> It might be common knowledge, but I want to point out that the usual COM implementation (atomic increment/decrement and free when refcount goes down to 0) is not thread-safe for shared pointers. That means you either have to guard all reads and writes with a lock to make the full assignment atomic or have to implement reference counting very different (e.g. deferred reference counting).

Since the implementation of AddRef()/Release() is up to the user, whether it uses locks or not and whether it supports shared or not is up to the user.

>> 12. AddRef() is not called when passed as the implicit 'this' reference.
>>
>
> Isn't this unsafe if a member function is called through the last existing reference and this reference is then cleared during execution of this member function or from another thread?

No. The caller of the function still retains a reference in that thread.

>
>> 13. Taking the address of, or passing by reference, any fields of an RC
>> object
>> is not allowed in @safe code. Passing by reference an RC field is allowed.
>
> Please note that this includes slices to fixed size arrays.

As I suggested, arrays would not be supported with this proposal - but the user can create ref counted array-like objects.

>>
>> 16. RC objects cannot be const or immutable.
>
> This is a bit of a downer. If the reference count is not within the object, this can be implemented.

Also, an exception could be made for the AddRef()/Release() functions.

>
> I feel I'm hijacking this proposal, but the step to library defined read/write barriers seems pretty small. Make AddRef, Release and assignment free template functions, e.g.
>
> void ptrConstruct(T,bool stackOrHeap)(T*adr, T p);
> void ptrAssign(T,bool stackOrHeap)(T*adr, T p);
> void ptrRelease(T,bool stackOrHeap)(T*adr);
>
> and we are able to experiment with all kinds of sophisticated GC algorithms including RC. Eliding redundant addref/release pairs would need some extra support though, I read that LLVM does something like this, but I don't know how.
>

It's pretty invasive into the code generation and performance, and could completely disrupt the C compatibility of D.
October 10, 2013
Jacob Carlborg wrote:

On Jun 25, 2013, at 11:00 PM, Walter Bright wrote:

> Updated incorporating Steven's suggestion, and some comments about
> shared/const/mutable/purity.

It's great that you're bringing this up. I think it's a good idea to add reference counting to D. Although I don't think I can add much to the discussion and Michel have a lot better knowledge about Objective-C than I have. All I can say is that I really want it to be compatible with Objective-C.
October 10, 2013
Michel Fortin wrote:

Le 26-juin-2013 à 5:38, Walter Bright  a écrit :

> On 6/26/2013 12:19 AM, Rainer Schuetze wrote:
>>
>> As Michel also said, the reference count does not have to be in inside the object itself, so we might want to allow reference counting on other types aswell.
>
> That opens the question of what is the point of other RC types? For example, C++ can throw any type - but it turns out that throwing anything but class types is largely pointless.

RC is just another garbage collection scheme. You might favor it for its performance characteristics, its determinism, or the lower memory footprint.

Or you might need it to interact with foreign code that relies on it (COM, Objective-C, etc.), in which case it needs to be customizable (use the foreign implementation) or be manually managed.

That's two different use cases. And in the later case you can't use the GC to release cycles because foreign code is using memory invisible to the GC. It is important to note that when foreign code calls AddRef you don't want the GC to collect that object, at least not until Release is called.


>> I don't think we should force linking this functionality with COM, the programmer can do this with a simple wrapper.
>
> Yeah, that's Michel's suggestion, and it's a good one.

It could also be done with user attributes:

	void x_init(ref X x);
	void x_destroy(ref X x);
	void x_assign(ref X a, X b); // retains a, releases b

	@arc!(x_init, x_destroy, x_assign)
	class X {}

This way you don't have to check for null in the generated code: the standalone function is in charge of that.

Also, this "assign" function here provides good opportunity for optimization in the RC implementation because you can update the two reference counts in a single operation (in the case where they're stored at the same place and are protected by the same lock). It's an improvement over making two separate function calls.


> No. The caller of the function still retains a reference in that thread.

This should also apply to all function arguments. The caller is better placed than the callee to elide redundant AddRef/Release pairs, so it should be the one in charge of retaining the object for the callee.


>>> 16. RC objects cannot be const or immutable.
>>
>> This is a bit of a downer. If the reference count is not within the object, this can be implemented.
>
> Also, an exception could be made for the AddRef()/Release() functions.

I'm not too fond of that idea.
October 10, 2013
Michel Fortin wrote:


Le 26-juin-2013 à 1:36, Walter Bright  a écrit :

> On 6/25/2013 6:09 PM, Michel Fortin wrote:
>> Instead, I think you should create a @noarc attribute for functions: it'll prevent the compiler for inserting any of those calls so it becomes the responsibility of the author to make those calls (which are then allowed). @noarc would be incompatible with @safe, obviously.
>
> It's a good point, but adding such an attribute to the function may be too coarse, for one, and may cause composition problems, for another. Maybe just disallowing it altogether is the best solution.

Well, it's mostly required to write runtime support functions. The attribute could be more obscure so people are less tempted to use it, but if you're going to implement the ref-counting code you'll need that.

>> ## More on reference counting
>>
>> I feel like I should share some of my thoughts here about a broader use of reference counting in D.
>>
>> First, we don't have to assume the reference counter has to be part of the object. Apple implements reference counting using global hash tables where the key is the address. It works very well.
>>
>> If we added a hash table like this for all memory allocated from the GC, we'd just have to find the base address of any memory block to get to its reference counter. I know you were designing with only classes in mind, but I want to point out that it is possible to reference-count everything the GC allocates if we want to.
>
> D would need manual, RC and GC to coexist peacefully.

The problem is how to make the three of those use the same codegen?

- Druntime could have a flag to disable/enable refcounting. It'd make the retain/release functions no-ops, but it'd not prevent the GC from reclaiming memory as it does today.
- Druntime could have a flag to disable/enable garbage collection (it already has). That'd prevent cycles from being collected, but you could use weak pointers to work around that or request a collection manually at the appropriate time.
- A @noarc (or similar) attribute at the function level could be used to prevent the compiler from generating function calls on pointer assignments. You could make a whole module @noarc if you want by adding "@noarc:" at the top.

Here's the annoying thing: @noarc is totally safe if reference counting is disabled and we rely entirely on the GC. @noarc is unsafe when reference counting is enabled.

>> The downside is that every assignment to a pointer anywhere has to call a function. While this is some overhead, it is more predictable than overhead from a GC scan and would be preferred in some situation (games I guess). Another downside is you have an object retained by being present on the stack frame of a C function, it'd have to be explicitly retained from elsewhere.
>
> Doesn't this make it impractical to mix vanilla C with D code? An important feature of D is this capability, without worrying about a "JNI" style interface.

It's not very different than with the GC today.

If you call a C function by giving it a ref-counted pointer argument, that memory block is guarantied to live at least for that call's lifetime (because it is retained by the caller). So simple calls to C functions are not a problem.

If the C function puts that pointer elsewhere you'll need to retain it some other way, but you have to do this with the GC too. If you're implementing a callback called from C you need to care about what you return because the caller's C code won't retain it, while with the GC you could manage if C code did not store that pointer outside of the stack.

I think that's all you have to worry about.

> As for D switching to a full refcounted GC for everything, I'm very hesitant for such a step. For one thing, reading the clang spec on all the various pointer and function annotations necessary is very off-putting.

Don't let Clang intimidate you. The Clang spec is about four to five time more complicated than needed because of autoreleased objects and because it supports weak pointers. Weak pointers can be implemented as a struct templates (as long as we have @noarc). And all those annotations are for special cases, when you need to break the rules. You don't use them when doing normal programming, well except for __weak.

October 10, 2013
Rainer Schuetze wrote:

On 26.06.2013 11:38, Walter Bright wrote:
>
> On 6/26/2013 12:19 AM, Rainer Schuetze wrote:
>>
>> I imagine a few (constrained) templated functions for the different
>> operations defined in the library could also do the job, though it
>> might drown compilation speed. Also getting help from the optimizer to
>> remove redundant calls will need some back doors.
>
> I don't see how this can be done without specific compiler knowledge in
> a memory safe way.

I currently don't see how it can be memory safe with this proposal.

>>> 3. Assignment to a class reference causes a call to AddRef() on the new
>>> value
>>> followed by a call to Release() on its original value.
>>
>> It might be common knowledge, but I want to point out that the usual
>> COM implementation (atomic increment/decrement and free when refcount
>> goes down to 0) is not thread-safe for shared pointers. That means you
>> either have to guard all reads and writes with a lock to make the full
>> assignment atomic or have to implement reference counting very
>> different (e.g. deferred reference counting).
>
> Since the implementation of AddRef()/Release() is up to the user,
> whether it uses locks or not and whether it supports shared or not is up
> to the user.

You have to put the lock around the pair of AddRef and Release, but if the compiler already splits this into two function calls, this cannot be done in the implementation.

>
>>> 12. AddRef() is not called when passed as the implicit 'this' reference.
>>>
>>
>> Isn't this unsafe if a member function is called through the last
>> existing reference and this reference is then cleared during execution
>> of this member function or from another thread?
>
> No. The caller of the function still retains a reference in that thread.

Hmmm, I guess I misunderstand the proposal. Assume for example a refcounted class R and this code

class R : RefCounted
{
    int _x;
    int readx() { return _x; }
}
int main()
{
    R r = new R;
    return r.readx();
}

According to 12. there is no refcounting going on when calling or executing readx. Ok, now what happens here:

class R : RefCounted
{
    int _x;
    int readx(C c)
    {
        c.r = null; // "standard" rc deletes r here
        return _x;  // reads garbage
    }
}
class C
{
    R r;
}
int main()
{
    C c = new C;
    c.r = new R;
    return c.r.readx(c);
}

This reads garbage or crashes if there is no reference counting going on when calling readx.

>
>>
>>> 13. Taking the address of, or passing by reference, any fields of an RC
>>> object
>>> is not allowed in @safe code. Passing by reference an RC field is
>>> allowed.
>>
>> Please note that this includes slices to fixed size arrays.
>
> As I suggested, arrays would not be supported with this proposal - but
> the user can create ref counted array-like objects.

Just to clarify, I meant taking a slice of a static array that is a field of a refcounted class. Is it forbidden to have a field like this in a refcounted class or is taking the address through slicing forbidden?

>>
>> I feel I'm hijacking this proposal, but the step to library defined
>> read/write barriers seems pretty small. Make AddRef, Release and
>> assignment free template functions, e.g.
>>
>> void ptrConstruct(T,bool stackOrHeap)(T*adr, T p);
>> void ptrAssign(T,bool stackOrHeap)(T*adr, T p);
>> void ptrRelease(T,bool stackOrHeap)(T*adr);
>>
>> and we are able to experiment with all kinds of sophisticated GC
>> algorithms including RC. Eliding redundant addref/release pairs would
>> need some extra support though, I read that LLVM does something like
>> this, but I don't know how.
>>
>
> It's pretty invasive into the code generation and performance, and could
> completely disrupt the C compatibility of D.

I don't see a big difference between a free function and a member function call, though the template character of it might hurt compilation performance.

Two more notes:

- I'm not sure it is mentioned, but I think you have to describe what happens when copying a struct. pre- and post-blit actions have to be taken if the struct contain pointers to refcounted objects.

> 10. Function returns have an AddRef() already done to the return value.

- A refcounted reference returned from a function (including new) would have to be Released if the return value is ignored or if only used as part of an expression.