Migrating an existing more modern GC to D's gc.d

David Bennett davidbennett at bravevision.com
Tue Apr 10 07:55:00 UTC 2018


On Tuesday, 10 April 2018 at 06:47:53 UTC, Jonathan M Davis wrote:
> As it stands, it's impossible to have thread-local memory 
> pools. It's quite legal to construct an object as shared or 
> thread-local and cast it to the other. In fact, it's _highly_ 
> likely that that's how any shared object of any complexity is 
> going to be constructed. Similarly, it's extremely common to 
> allocate an object as mutable and then cast it to immutable 
> (either using assumeUnique or by using a pure function where 
> the compiler does the cast implicitly for you if it can 
> guarantee that the return value is unique), and immutable 
> objects are implicitly shared.
>

(Honest question:) Do people really cast from local to 
shared/immutable and expect it to work?
(when ever I cast something more complex then a size_t I almost 
expect it to blow up... or break sometime in the future)

That said, I can understanding building a shared object from 
parts of local data... though I try to keep my thread barriers as 
thin as possible myself. (meaning I tend to copy stuff to the 
shared and have as few shared's as possible)

>
> At minimum, there would have to be runtime hooks to do 
> something like move an object between pools when it is cast to 
> shared or immutable (or back) in order to ensure that an object 
> was in the right pool, but if that requires copying the object 
> rather than just moving the memory block, then it can't be 
> done, because every pointer or reference pointing to that 
> object would have to be rewritten (which isn't supported by the 
> language).
>

A hook for local to cast(shared) could work... but would require 
a DIP I guess. I was hoping to make a more incremental 
improvement the the GC.

>
> Also, it would be a disaster for shared, because the typical 
> way to use shared is to protect the shared object with a mutex, 
> cast away shared so that it can be operated on as thread-local 
> within that section of code, and then before the mutex is 
> released, all thread-local references then need to be gone. e.g.
>
>
> synchronized(mutex)
> {
>     auto threadLocal = cast(MyType)mySharedObject;
>
>     // do something with threadLocal...
>
>     // threadLocal leaves scope and is gone without being cast 
> back
> }
>
> // all references to the shared object should now be shared
>

Yeah thats why I was still scanning all thread stacks and pages 
when marking global data.
So a shared -> local is a no op but the other way needs thought.

>
> You really _don't_ want the shared object to move between pools
> because of that cast (since it would hurt performance), and in 
> such a
> situation, you don't usually cast back to shared. Rather, you 
> have a shared
> reference, cast it to get a thread-local reference, and then 
> let the
> thread-local reference leave scope. So, the same object 
> temporarily has both
> a thread-local and a shared reference to it, and if it were 
> moved to the
> thread-local pool with the cast, it would never be moved back 
> when the
> thread-local references left scope and the mutex was released.
>
> Having synchronized classes as described in TDPL would make the 
> above code cleaner in the cases where a synchronized class 
> would work, but the basic concept is the same. It would still 
> be doing a cast underneath the hood, and it would still have 
> the same problems. It just wouldn't involve explicit casting. 
> shared's design inherently requires casting away shared, so it 
> just plain isn't going to play well with anything that doesn't 
> play well with such casts - such as having thread-local heaps.
>

I would think a shared class would never be marked as a 
THREAD_LOCAL as it has a shared member.

>
> Also, IIRC, at one point, Daniel Murphy explained to me some 
> problem with classes with regards to the virtual table or the 
> TypeInfo that inherently wouldn't work with trying to move it 
> between threads. Unfortunately, I don't remember the details 
> now, but I do remember that there's _something_ there that 
> wouldn't work with thread-local heaps. And if anyone were to 
> seriously try it, I expect that he could probably come up with 
> the reasons again.
>
> Regardless, I think that it's clear that in order to do 
> anything with thread-local pools, we'd have to lock down the 
> type system even further to disallow casts to or from shared or 
> immutable, and that would really be a big problem given the 
> inherent restrictions on those types and how shared is intended 
> to be used. So, while it's a common idea as to how the GC could 
> be improved, and it would be great if we could do it, I think 
> that it goes right along with all of the other ideas that 
> require stuff like read and write barriers everywhere and thus 
> will never be in D's GC.
>
> - Jonathan M Davis

Yeah I thought it would have issues, thanks for your feedback!

I'll see if I can come up with a better idea that doesn't break 
as much stuff.


More information about the Digitalmars-d mailing list