fibers B1.1: per-fiber context root is library-only (no compiler change)

A fiber needs its own root Context (the spawner's snapshot), not the
ambient one. Probed whether that needs compiler support: it does not.
context is an implicit slot-0 *Context param (call-carried, rides the
callee's own stack) and push Context allocates on the caller frame —
never TLS, never re-read from the __sx_default_context global mid-stack.
So the spawn convention is pure library sx:

  snap := context;            // snapshot the spawner's context
  f := Fiber.{ root = snap }; // store it
  push f.root { entry(args) } // trampoline installs it as the fiber root

examples/1804-concurrency-context-snapshot.sx locks it: a trampoline
running under ambient ctx 99 installs a stored snapshot (42); the body
reads 42, and the push scope restores 99 on exit. No fiber runtime yet
(B1.3) — this proves the plumbing it builds on.

The design doc's "lower context as swappable indirection, never raw
TLS" guarded a non-problem — context was already param-carried.

Suite green (726/0).
This commit is contained in:
agra
2026-06-20 17:09:26 +03:00
parent a7fe165684
commit bab4886346
6 changed files with 117 additions and 31 deletions

View File

@@ -1,8 +1,8 @@
# PLAN-FIBERS — Stream B1 (fibers + Io + M:1 scheduler)
> **STATUS: 🚧 in progress.** B1.0 (`abi(.naked)` codegen) ✅ complete — emits a real LLVM
> `naked` function end-to-end (decl / generic / pack paths; examples 1800/1801/1802 + unit
> test). Next step = **B1.1** (per-fiber `context` root — probe-first, likely library-only).
> **STATUS: 🚧 in progress.** B1.0 (`abi(.naked)` codegen) ✅ + B1.1 (per-fiber `context`
> root — zero compiler change, library convention) ✅ complete. Next step = **B1.2** (`Io`
> interface + `context.io` + `Future` + `cancel()`).
Carved from [PLAN-POST-METATYPE.md](PLAN-POST-METATYPE.md) Stream B (§B1) + the
design-of-record [../design/execution-evolution-roadmap.md](../design/execution-evolution-roadmap.md)
@@ -174,14 +174,14 @@ B1.0 (`.naked`) forces these plumbing sites:
*enables* B1.3's `swap_context(from, to)`. Locked by `1803-concurrency-naked-asm-param.sx`.
Pack `.naked` (variadic + naked, nonsensical) left unsupported → loud verifier error.
### B1.1 — per-fiber `context` root (probe-first; likely zero compiler change)
- **B1.1a (probe + lock)** — write a probe (`.sx-tmp/`) + an `18xx` example that snapshots a
`Context` (e.g. a custom allocator pushed via `push Context`) and confirms it is carried by
slot 0 across an ordinary call chain (it is — grounded). If the probe shows a fiber-entry
trampoline can pass a snapshotted ctx as slot 0 with **no compiler change**, this phase is a
**library convention doc** (record it in the checkpoint) + a corpus example locking the
behavior. If (and only if) the probe surfaces a real compiler gap (a path re-reads
`__sx_default_context` mid-stack), file it as a step here and size it then.
### B1.1 — per-fiber `context` root — ✅ COMPLETE (zero compiler change)
Probe confirmed the spawn convention works with ordinary language features: snapshot
`context` (`snap := context`), store it in a struct, and `push f.root { entry(args) }` from a
trampoline running under a different ambient context — the body reads the snapshot (via the
implicit slot-0 `*Context` param), not the ambient ctx, and `push` restores ambient on exit.
No path re-reads `__sx_default_context` mid-stack ⇒ **no compiler obligation**; this is a pure
library convention. Locked by `examples/1804-concurrency-context-snapshot.sx` (`fiber root:
42` / `ambient after: 99`). The design doc's "never raw TLS" guarded a non-problem.
### B1.2 — A1: `Io` interface + `context.io` + `Future` + `cancel()` API
Library-only. `Io` as a protocol added to `Context` (mirror `Allocator`). `Future`/`cancel`