RTS: Pooled adjustor allocation
Adjustors are small bits of code produced by the runtime to facilitate calls from C into Haskell, principally to implement foreign exports
. As adjustors are executable code, we currently use a rather simplistic allocation strategy, allocating one page per adjustor.
However, in #20349 (closed) I noticed that some packages (e.g. terminfo
, used by GHCi) allocate considerable quantities of adjustors, making this design somewhat painful. Moreover, when working on the linker changes associated with #21019 (closed) I noticed that on Windows the situation is even worse: Windows can only map memory in units of the allocation granularity, which is 64kBytes on most machines. Consequently, each adjustor, which consists of only a handful of bytes of machine code, can end up consuming 64kByte of memory. In !7448 (closed) this manifested as the failure of T10296a
, which allocates 65000 adjustors (and therefore over 4GB of memory on Windows).
This MR resolves this by refactoring the allocation and construction of adjustors. We introduce a new allocator abstraction, AdjustorPool
(described in Note [Adjustor pools]
), which is responsible for allocating and constructing adjustors. We then refactor the AMD64 adjustor logic (for both Windows and POSIX platforms) to use this new infrastructure.