On Friday, 12 February 2016 at 19:12:48 UTC, Andrei Alexandrescu wrote:
https://github.com/D-Programming-Language/phobos/pull/3991

A short while ago Dicebot discussed the notion of using the allocator to store the reference count of objects (and generally metadata). The allocator seems to be a good place because in a way it's a source of "ground truth" - no matter how data is qualified, it originated as untyped mutable bytes from the allocator.

So after thinking a bit I managed to convince myself that the affixes in an AffixAllocator can be accessed with removing immutable, but without actually breaking any guarantee made by the type system. (Affixes are extra bytes allocated before and after the actual allocation.) The logic goes as follows:

* If the buffer is mutable, then the allocator assumes it hasn't been shared across threads, so it returns a reference to a mutable affix.

* If the buffer is const, then the allocator must conservatively assume it might have been immutable and subsequently shared among threads. Therefore, several threads may request the affix of the same buffer simultaneously. So it returns a reference to a shared affix.

* If the buffer is shared, then the allocator assumes again several threads may access the affix so it returns a reference to a shared affix.

One simple way to look at this is: the allocator keeps an associative array mapping allocated buffers to metadata (e.g. reference counts). The allocated buffers may be immutable, which doesn't require the metadata to be immutable as well. The only difference between an approach based on an associative array and AffixAllocator is that the latter is faster (the association is fixed by layout).


Destroy!

Andrei

So if I may, I think we should avoid affix data in the general case.

Providing some metadata in the allocate is in itself a good idea. Locating these data with the object is usually not : - Mutating the metadata will create sharing overhead on the whole cache line. Sharing of immutable would become inefficient. - It tends to create allocation size that aren't friendly to underlying allocators. For instance, an alocation of size 2^n + 8 bumps you to the next size class, often 2^(n+1) or alike. This creates a lot of internal fragmentation. - Buffer overflow/underflow WILL spill in the alocator metadata. You don't want that. This pretty much guaranteed that the worse thing that can happen will happen: corrupting the alocator.

jemalloc moved away from using them for small runs for these reasons.

Reply via email to