April 22, 2014
On Tuesday, 22 April 2014 at 09:40:15 UTC, Ola Fosheim Grøstad wrote:
>    if( CAS_SET_BIT(ref+32,THREADID)==THREADID ){

Make that:

 if( CAS_SET_BIT(ref+32,THREADID) == (1<<THREADID) ){
April 22, 2014
On Thursday, 17 April 2014 at 19:51:38 UTC, Walter Bright wrote:
> On 4/17/2014 10:41 AM, Dicebot wrote:
>> On Thursday, 17 April 2014 at 16:57:32 UTC, Walter Bright wrote:
>>>> With current limitations @nogc is only useful to verify that embedded code which
>>>> does not have GC at all does not use any GC-triggering language features before
>>>> it comes to weird linker errors / rt-asserts. But that does not work good either
>>>> because of next problem:
>>>
>>> Remember that @nogc will be inferred for template functions. That means that
>>> whether it is @nogc or not will depend on its arguments being @nogc, which is
>>> just what is needed.
>>
>> No, it looks like I have stated that very wrong because everyone understood it
>> in completely opposite way. What I mean is that `put()` is NOT @nogc and it
>> still should work. Same as weakly pure is kind of pure but allowed to mutate its
>> arguments, proposed "weakly @nogc" can only call GC via functions directly
>> accessible from its arguments.
>
> I don't see value for this behavior.

It turns out to have enormous value. I will explain this in my DConf talk. A little preview:
Almost all of our code at Sociomantic obeys this behaviour, and it's probably the most striking feature of our codebase. By "almost all" I mean probably 90% of our code, including all of our libraries. Not just the 5% - 10% that could marked as @nogc according to your DIP.

The key property it ensures is, if you make N calls to the function, the number of GC allocations is in O(1). We don't care if makes 0 allocations or 17.

We're not really interested in whether a function uses the GC or not, since most interesting functions do need to do some memory allocation.

Ideally, we'd want an attribute which could applied to *all* of Phobos, except for some convenience functions. We have no interest in library code which doesn't behave in that way.

April 22, 2014
On Mon, 21 Apr 2014 17:52:30 -0400, Ola Fosheim Grøstad <ola.fosheim.grostad+dlang@gmail.com> wrote:

> Here are two very good reasons to avoid extensive ref-counting:
>
> 1. transactional memory ( you don't want a lock on two reads )
>
> 2. cache coherency ( you don't want barriers everywhere )
>
> Betting everything on ref counting is the same as saying no to upcoming CPUs.
>
> IMO that means ARC is DOA. It might be useful for some high level objects… but I don't understand why one would think that it is a good low level solution. It is a single-threaded solution.

Single threaded ARC can go a long way in D. We statically know whether data is shared or not.

-Steve
April 22, 2014
On Mon, 21 Apr 2014 19:02:53 -0400, Walter Bright <newshound2@digitalmars.com> wrote:

> On 4/21/2014 1:29 PM, Steven Schveighoffer wrote:
>> I think you are misunderstanding something. This is not for a pervasive
>> ARC-only, statically guaranteed system. The best example he gives (and I agree
>> with him) is iOS. Just look at the success of iOS, where the entire OS API is
>> based on ARC (actually RC, with an option for both ARC and manual, but the
>> latter is going away). If ARC was "so bad", the iOS experience would show it.
>> You may have doubts, but I can assure you I can build very robust and performant
>> code with ARC in iOS.
>
> The thing is, with iOS ARC, it cannot be statically guaranteed to be memory safe.

So?

> This makes it simply not acceptable for D in the general case.

Because it can't live beside all the other unsafe code in D? I don't get it...

> It "works" with iOS because iOS allows all kinds of (unsafe) ways to escape it, and it must offer those ways because it is not performant.

I think we're officially going in circles here.

> Kinda sorta memory safe, mostly memory safe, etc., is not a static guarantee.
>
> There is JUST NO WAY that:
>
>      struct RefCount {
>          T* data;
>          int* count;
>      }
>
> is going to be near as performant as:
>
>      T*

Again with the straw man!

> 1. A dereference requires two indirections. Cache performance, poof!
>
> 2. A copy requires two indirections to inc, two indirections to dec, and an exception unwind handler for dec.
>
> 3. Those two word structs add to memory consumption.

Consider the straw man destroyed :)

> As you pointed out, performant code is going to have to cache the data* value. That cannot be guaranteed memory safe.
>
>
>>> I can't reconcile agreeing that ARC isn't good enough to be pervasive with
>>> compiler technology eliminates unnecessary ARC overhead.
>> It's pretty pervasive on iOS. ARC has been around since iOS 4.3 (circa 2011).
>
> Pervasive means "for all pointers". This is not true of iOS. It's fine for iOS to do a half job of it, because the language makes no pretensions about memory safety. It is not fine for D to replace a guaranteed memory safe system with an unsafe, hope-your-programmers-get-it-right, solution.
>

Totally agree, which is why nobody is saying that.

-Steve
April 22, 2014
On Tuesday, 22 April 2014 at 13:11:55 UTC, Steven Schveighoffer wrote:
> Single threaded ARC can go a long way in D.

Not without changing language semantics/mechanisms?

>We statically know  whether data is shared or not.

I don't understand how you can know this when you allow foreign function invocation.

Even thread local globals can leak into another thread by mistake, unnoticed? Meaning random crashes that are hard to debug?

April 22, 2014
On Tue, 22 Apr 2014 09:29:28 -0400, Ola Fosheim Grøstad <ola.fosheim.grostad+dlang@gmail.com> wrote:

> On Tuesday, 22 April 2014 at 13:11:55 UTC, Steven Schveighoffer wrote:
>> Single threaded ARC can go a long way in D.
>
> Not without changing language semantics/mechanisms?
>
>> We statically know  whether data is shared or not.
>
> I don't understand how you can know this when you allow foreign function invocation.

Can you explain this?

> Even thread local globals can leak into another thread by mistake, unnoticed? Meaning random crashes that are hard to debug?

By mistake? How?

-Steve
April 22, 2014
On Tuesday, 22 April 2014 at 13:39:54 UTC, Steven Schveighoffer wrote:
> On Tue, 22 Apr 2014 09:29:28 -0400, Ola Fosheim Grøstad Can you explain this?

When you use a C/C++ framework you don't know what happens to the pointers you hand to it.

You also don't know which threads call your D-functons from that framework. (Assuming the framework is multi-threaded). To know this you are required to know the internals of the framework you are utilizing or inject runtime guards into your D functions?

> By mistake? How?

By insertion into a global datastructure that happens at a lower layer than the higher level you allocate on.
April 22, 2014
On Tue, 22 Apr 2014 09:48:28 -0400, Ola Fosheim Grøstad <ola.fosheim.grostad+dlang@gmail.com> wrote:

> On Tuesday, 22 April 2014 at 13:39:54 UTC, Steven Schveighoffer wrote:
>> On Tue, 22 Apr 2014 09:29:28 -0400, Ola Fosheim Grøstad Can you explain this?
>
> When you use a C/C++ framework you don't know what happens to the pointers you hand to it.

Those are typically well-documented, but yes, you rely on "insider" knowledge. You can mark C functions with the appropriate attributes so the D compiler can enforce this for you. I think we should make reference counting work, as long as you don't call mischievous library code. We take a similar approach to other safety aspects of D.

> You also don't know which threads call your D-functons from that framework. (Assuming the framework is multi-threaded). To know this you are required to know the internals of the framework you are utilizing or inject runtime guards into your D functions?

Or just mark those objects sent into the framework as shared. Having multi-threaded RC isn't bad, just not as efficient.

One thing that would be nice is to allow moving a data pointer from one thread to another. In other words, as long as your data is contained, it can pass from one thread to another, and still be considered unshared.

I think sooner or later, we are going to have to figure that one out.

>
>> By mistake? How?
>
> By insertion into a global datastructure that happens at a lower layer than the higher level you allocate on.

I think this is what you are talking about above, or is there something else?

-Steve
April 22, 2014
On Tuesday, 22 April 2014 at 14:07:47 UTC, Steven Schveighoffer wrote:
>> know this you are required to know the internals of the framework you are utilizing or inject runtime guards into your D functions?
>
> Or just mark those objects sent into the framework as shared. Having multi-threaded RC isn't bad, just not as efficient.

Actually, when I think of it, guards probably would be cheap. All you have to do is to store the thread-context-pointer-register into a global when the thread starts up. Then just do a simple if-test at the function invocation. (assuming the register doesn't change over time).

Actually, it could be done as a self-modifying pass at startup… That would make it a register test against an immediate value, no memory buss implications.

> One thing that would be nice is to allow moving a data pointer from one thread to another. In other words, as long as your data is contained, it can pass from one thread to another, and still be considered unshared.

Yes, that sounds plausible.

> I think this is what you are talking about above, or is there something else?

You are right :).

Ola.
April 22, 2014
On Tuesday, 22 April 2014 at 06:51:40 UTC, Ola Fosheim Grøstad
wrote:
> On Monday, 21 April 2014 at 23:02:54 UTC, Walter Bright wrote:
>> There is JUST NO WAY that:
>>
>>    struct RefCount {
>>        T* data;
>>        int* count;
>>    }
>>
>
> This is actually quite efficient compared to the standard NSObject which uses a hashtable for refcounting:

iOS now on 64-bit processors doesn't necessarily use a hashtable
for refcounting. Basically, only 33 bits of the 64-bit pointer
are used to actually refer to an address, then 19 of the
remaining bits are used to store an inline reference count. Only
if the inline reference count exceeds these 19 bits (very rare)
do they switch to using a hashtable. It was one of the large
benefits of switching to ARM64 for the iPhone 5.