1
0
Fork 0
forked from fun/fun

More documentation about internals. No code changes (0.38.0)

This commit is contained in:
Johannes Findeisen 2026-01-28 16:42:16 +01:00
commit 40c509626e

View file

@ -285,6 +285,50 @@ We chose isolated state (like Lua) rather than a single global lock (like Python
- PerVM scheduler: Green threads are multiplexed within a VM. Preemption is cooperative with periodic safe points; an optional timeslice can yield between bytecode instruction groups when `FUN_DEBUG` or tracing is enabled.
- PerVM GC: Stoptheworld, perVM. No global stoptheworld across VMs. A GC in one VM does not pause others.
### Shared memory as the escape hatch
Message passing and serialization are the defaults. When copying becomes too expensive, use shared memory — but keep it outside the tracing heaps and very constrained:
- Offheap, opaque buffers: Use `fun_shared_buffer` for large blobs (e.g., images, JSON bytes, tensors). These are refcounted, live outside any VM heap, and are immutable from the VMs perspective.
- No heap pointers inside: Shared regions must not contain pointers into any VM heap. Treat them as raw bytes plus size/stride metadata.
- Synchronization via atomics/futexes (host side): If you need concurrent producers/consumers over shared buffers, build lockfree queues or channels on the host using atomics. The VM sees only opaque handles.
- Lifetime: Governed by explicit ownership (retain/release), epochs, or arena lifetime — not by any VMs GC.
This provides zerocopy handoff without coupling VMs or their collectors.
### Do perVM GCs need to stoptheworld for shared regions?
It depends on what “shared” means. Our design keeps perVM GCs independent by default:
1) Untraced shared regions (recommended)
- Contents contain no GC pointers; GCs never scan them.
- Each VM can collect independently; no crossVM safepoints or barriers are required.
- Lifetime is managed explicitly (refcounts/finalizers/epochs). This is how `fun_shared_buffer` works.
2) Shared, GCmanaged objects (generally avoid)
- If objects with pointers are genuinely shared across VMs, you need one of:
- Global safepoints with coordinated stoptheworld across participants; or
- A concurrent/incremental GC with crossVM read/write barriers and either a shared heap or remembered sets; or
- Replacing tracing with atomic refcounting for the shared objects.
- Complexity, latency, and correctness risks increase substantially. Fun intentionally avoids this mode.
3) Hybrids
- Immutable shared objects with global refcounts and no pointers back into perVM heaps.
- Copyonwrite pages or rope/cord structures backed by `fun_shared_buffer`.
- Message passing that can “adopt” an offheap buffer by transferring ownership instead of copying.
### Practical guidance
- Default to isolated VMs and message passing.
- Use `fun_shared_buffer` only for zerocopy payloads; keep them untraced and pointerfree relative to VM heaps.
- Clearly document and enforce what types are shareable; forbid crossVM heap references.
- If you ever consider sharing GCmanaged objects, budget for global safepoints or a fully barriered concurrent GC — neither is planned for Funs core.
### Bottom line
- Isolates are the sensible default; sharedmemory primitives are the performance escape hatch.
- With offheap, untraced shared regions, perVM GCs stay independent and never have to stop the world across other VMs.
### Embedding patterns
- Parallelism: Create N VMs for N cores, wire them with channels or shared buffers. No global lock contention.