Future Directions¶
Thunk Serialization¶
Unlike compact regions (normal form only), ghc-fastboot can freeze thunks — unevaluated computations. A frozen Map where 90% of entries are unevaluated thunks takes near-zero space per thunk and evaluates on demand after thaw. This is a unique capability: lazy persistence.
The walker encounters a thunk, copies it as-is (info table pointer + free variables), and records relocations for its code pointer. On thaw, the thunk is a valid GHC closure that evaluates normally when forced.
Limitation: BLACKHOLEs cannot be frozen. A BLACKHOLE means a thread is mid-evaluation — the info table has been overwritten and the original thunk is lost. Freeze must happen when evaluation is quiescent (no in-flight thunk evaluation for the target data).
Multi-Runtime Shared Images¶
The fixed VA design enables multiple Haskell runtimes to share frozen data:
-
Shared page cache: multiple processes mmap the same snapshot file. The kernel shares physical pages via the page cache. Each process gets CoW semantics via
MAP_PRIVATE. -
Daemon architecture: a fastboot daemon holds snapshots in shared memory, manages lifecycle (freeze once, serve to many, evict when stale), verifies binary compatibility, and provides fds to clients.
-
Cross-process thunk evaluation: Runtime A thaws a frozen image, encounters a thunk. Instead of evaluating locally, it delegates to Runtime B (which has the same image at the same VA). B evaluates the thunk, writes an IND (indirection) closure pointing to the result in a shared region. A follows the IND transparently.
Composable Images¶
Frozen images can reference other frozen images. Each image gets a VA slot in the 1TB range:
Image A (VA slot 900GB): dictionary, 10M entries
Image B (VA slot 901GB): search index, pointers into A
Image C (VA slot 902GB): user model, references A and B
Cross-image pointers are absolute addresses. If both images are loaded at their expected VAs — zero relocation. The snapshot header would carry a dependency table listing required images and their expected VAs.
This is a data linker: freeze = compile, snapshot = object file, daemon = dynamic linker/loader. Like shared libraries but for data structures.
Distributed HPC¶
The packed snapshot format is network-ready:
- Send: the snapshot buffer is a contiguous byte sequence, sendable via RDMA or TCP
- Receive: mmap into the target VA, apply code pointer relocations (same binary → single delta)
- Result: native GHC closures in the remote heap, no deserialization
For distributed-process / Cloud Haskell, this replaces Binary serialization with direct heap transfer. Messages become mmap'd closure graphs instead of serialized byte streams.
With thunk serialization, this enables work stealing: send a partially-evaluated computation (thunk + its closure environment) to another node for evaluation. The thunk's free variables are in the frozen image, valid at the same VA on the remote node.
Cross-Runtime Thunk Evaluation¶
Multiple runtimes share a frozen image (MAP_PRIVATE, CoW). Each evaluates different thunks. Results shared via IND closures pointing into shared regions. Fixed VA makes cross-runtime pointers work without coordination.
The mechanism:
- Runtime A and B both mmap the same snapshot at the same fixed VA
- A forces thunk T₁, which gets overwritten with
IND → result₁(in A's CoW pages) - B forces thunk T₂ →
IND → result₂(in B's CoW pages) - A shared-memory region at a known VA holds evaluated results
- A protocol (or simply
MAP_SHAREDfor the result region) allows both runtimes to see each other's evaluated thunks
This is speculative but architecturally sound: GHC's indirection mechanism already handles this pattern for single-runtime thunk evaluation.
TSO Serialization (Research Direction)¶
GHC's green threads (TSOs) are heap objects with heap-allocated stacks. At a safe point, all execution state is in the TSO/stack — no native TLS, no kernel thread state. This makes them theoretically serializable.
However, stack frames contain return addresses that point mid-function (not to entry points). These cannot be resolved via dlsym — they encode control flow state in the program counter position. Serializing stacks would require compiler support to make continuation points addressable as symbols.
Practical boundary: freeze data (closures, thunks, functions), not control flow (stacks, threads). This covers virtually all real use cases.
Linear Types for Safe Lifecycle¶
Linear Haskell types can enforce safe lifecycle management for shared images:
-- Daemon hands out linear tokens
acquire :: ImageName -> (Token %1 -> IO a) -> IO a
-- Token ensures exactly-once release
withImage :: Token %1 -> (forall s. Image s -> IO a) -> (a, Token)
Linearity guarantees: no use-after-unmap (the token is consumed), no double-free (exactly-once semantics), daemon knows when all clients have released.
Not Yet Implemented¶
- Merkle fingerprint computation
- Binary hash verification (
binary_hashfield zeroed) fastboot-migrateCLI tool- Lazy bdescr init (userfaultfd)
withFreezescoped Haskell API