Description
We use a very simple, first-fit free list for allocation in the DRC collector right now:
We should use something better, that has size classes and good hueristics and all that.
But also, we would ideally not write and maintain what is essentially our own malloc
implementation ourselves, since getting all the details right and tuning them correctly for a variety of workloads is a lot of effort. The problem is that our malloc is outside the memory space that it is divvying up and parceling out: it is not inside the GC heap using and returning pointers within the GC heap, it is in the VM on the outside and is returning indices into the sandboxed region that makes up the GC heap, rather than pointers.
But... why not just compile dlmalloc
(or something) to Wasm, have dlmalloc
use the GC heap as its linear memory, and make GC allocations call dlmalloc
's allocation and deallocation routines? That would give us a battle-hardened allocator that is most certainly faster than our free list pretty much For Free and with trivial long-term maintenance burden. Compiling dlmalloc
to Wasm, with the right flags and exported symbols, results in a ~5-6 KiB binary that doesn't use any Wasm globals or funcref
tables and uses only ~500 bytes of static data. It seems very doable.
This will rely on a lot of the same kind of infrastructure we want to have for compile-time builtins.
Random kinks to work out:
- Do we compile
dlmalloc
into every GC-type-using module, similar to trampolines? (Including modules that just useexternref
and not full Wasm GC.)- This means there would be some duplicate copies of the code when you load multiple GC-type-using modules in the system, which is fine from a correctness POV, but is undesirable from a disk space usage POV, and a memory usage POV if you're on a system without virtual memory.
- Or do we try and have only a single copy of
dlmalloc
in a system that is running multiple modules?- We could compile
dlmalloc-gc-heap.wasm
on demand the first time a gc-type-using module is compiled, but that requires that wasmtime was built with a compiler itself. - We could compile
dlmalloc-gc-heap.wasm
at Wasmtime build time andinclude_bytes!(...)
it into the Wasmtime binary, but that means additional, bootstrap-y, cyclic dependencies where you need a wasmtime to build wasmtime. - We could require that configuring Wasmtime to use the DRC collector means you have to give a
wasmtime::Drc
object to thewasmtime::Config::collector
method, and you can eitherwasmtime::Drc::new()
when wasmtime is built with a compiler orwasmtime::Drc::from_serialized(...)
otherwise. However, this raises questions aboutimpl Default for Config
sinceConfig
contains the configured collector, which by default is the DRC collector. Does it no longer implDefault
when there is no compiler? Do we change the default collector when there is no compiler? Do we just remove thatDefault
impl?
- We could compile