This CL introduces the 32 & 64-bit primary allocators, and associated
Local Cache. While the general idea is mostly similar to what exists
in sanitizer_common, it departs from the original code somewhat
significantly:
- the 64-bit primary no longer uses a free array at the end of a region but uses batches of free blocks in region 0, allowing for a convergence with the 32-bit primary behavior;
- as a result, there is only one (templated) local cache type for both primary allocators, and memory reclaiming can be implemented similarly for the 32-bit & 64-bit platforms;
- 64-bit primary regions are handled a bit differently: we do not reserve 4TB of memory that we split, but reserve NumClasses * 2^RegionSizeLog, each region being offseted by a random number of pages from its computed base. A side effect of this is that the 64-bit primary works on 32-bit platform (I don't think we want to encourage it but it's an interesting side effect);
Local cache and SizeClassAllocator are very tightly coupled. It's pretty difficult to understand what's going on.
For example, a call to SizeClassAllocatorLocalCache::allocate takes a SizeClassAllocator as a param and may call popBatch on that allocator. popBatch takes the current SizeClassAllocatorLocalCache as a param and passes it down through populateFreeList and populateBatch which may then call SizeClassAllocatorLocalCache::createBatch. createBatch may call allocate, which may then call into SizeClassAllocator::popBatch. Which makes a very confusing and ugly cycle in the call graph (whether it can happen in practice or not).
Surely there's a less convoluted way to implement this...