Just about every operating system provides a mechanism for directly allocating and deallocating memory at the page level (ie. not malloc/free or new/delete). The functions to do this vary from OS to OS:
- Windows: VirtualAlloc/FreeAlloc.
- Posix (e.g. Mac and Linux): mmap/munmap.
- Mac also has: vm_allocate/vm_deallocate.
So it’s very natural to add an abstraction layer: your own functions (let’s call them Map and Unmap) that use conditional compilation to choose the appropriate OS-specific call.
An abstraction layer like this appears in lots of software projects. Firefox happens to incorporate code from a lot of other projects, and so what happens is you end up with lots of duplicate abstraction layers. For example, in the JS engine alone we have five Map/Unmap abstraction layers.
- In js/src/jsgcchunk.cpp, used to allocate chunks for the GC heap.
- in js/src/vm/Stack.cpp, used to allocate some stack space.
- In js/src/nanojit/avmplus.cpp, used to allocate space for code generated by the trace JIT.
- In js/src/assembler/jit/ExecutableAllocator*.cpp, used to allocate space for code generated by the method JIT.
- In js/src/ctypes/libffi/src/dlmalloc.c, used to allocate chunks of memory that are handed out in pieces by the heap allocator defined in that file.
The duplication of 3, 4 and 5 are understandable — they all involve large chunks of code that were imported from other projects. (Furthermore, you can see that ctypes/ has its own heap allocator, thus duplicating jemalloc’s functionality.) The duplication between 1 and 2 is less forgiveable; neither of those cases were imported and so they should share an abstraction layer.
How many other Map/Unmap abstraction layers are there in the rest of Firefox? The JS engine may be more guilty of this than other parts of the code. Is there a sane way to avoid this duplication in a world where we import code from other projects?