Skip to content

Commit 5e33a99

Browse files
olwangclaude
andcommitted
docs: cross-isolate message API — feasibility + design (not yet built)
The fourth spec-todo roadmap item (§20.2-3) has no runtime foundation: the runtime is strictly single-isolate (one cooperative-task heap; the channel is an explicit single-isolate Rc<RefCell> MPSC), so "managed handles never cross isolates" has no boundary to enforce yet — exactly why the spec gates it on "the isolate model maturing first." Rather than fake a heap-sharing cooperative-task channel as a "cross-isolate" boundary, record the smallest sound implementation plan (cross-isolate-design.md): a static is_cross_isolate_safe(T) payload rule plus a distinct Mailbox<T> surface over the cooperative scheduler. spec-todo.md updated to mark it blocked-on-foundation with the plan; linked from the docs index. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ba63686 commit 5e33a99

3 files changed

Lines changed: 89 additions & 4 deletions

File tree

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ LLMs); everything else lives here.
1515
| [DEVELOPMENT.md](DEVELOPMENT.md) | Local verification flow and development discipline. |
1616
| [DOCKER.md](DOCKER.md) | Containerized, cross-platform dev environment (Docker / VS Code / Codespaces). |
1717
| [spec-todo.md](spec-todo.md) | Prioritized list of unimplemented spec surface (the §3.2 / §20.1 superset). |
18+
| [cross-isolate-design.md](cross-isolate-design.md) | Feasibility + smallest-sound-slice plan for the cross-isolate message API (§20.2-3, not yet built). |
1819

1920
## Implementation-planning specs (not yet normative)
2021

docs/cross-isolate-design.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Cross-isolate message API — design & feasibility (spec §20.1-B / §20.2-3)
2+
3+
Status: **not implemented — blocked on foundational runtime work** (the spec gates
4+
it on "the isolate model maturing first"). This note records the investigation and
5+
the smallest sound implementation plan so the work can be picked up directly.
6+
7+
## Goal (from the spec)
8+
9+
Typed send/receive channels **between isolates**: payloads are owned/Copy data or
10+
values moved with `take`; **managed handles never cross**; single ownership is
11+
enforced statically (not by runtime convention); `take`-based move is the
12+
no-shared-alias transfer path (zero-copy when representation permits).
13+
14+
## Why it isn't a small change today
15+
16+
The runtime is **strictly single-isolate**. Concurrency is cooperative tasks on
17+
one thread sharing **one heap**:
18+
19+
- `crates/runtime/src/channel.rs` is an explicit "single-isolate MPSC" using
20+
`Rc<RefCell<ChannelState<T>>>` (no `Send`/`Sync`, no `Arc<Mutex>`).
21+
- The reg-VM scheduler (`reg_vm/mod.rs`: `tasks`, `ready_queue`, `Wait`,
22+
`satisfy_waiters`) drives many tasks, but they share the same `Rc` pool —
23+
`task_group` children are isolate-**local**.
24+
- There is no construct that creates a second execution context with its own heap;
25+
a "second isolate" would still alias the same managed `Rc`s.
26+
27+
So "managed handles never cross isolates" has no boundary to be enforced *at*
28+
today — there is only one heap.
29+
30+
## Smallest sound slice (recommended, ~1–2 weeks; holds VM↔compiled parity)
31+
32+
Reuse the cooperative scheduler; make the isolate boundary a **static + runtime
33+
value-transfer contract** rather than a separate OS thread/heap. Soundness comes
34+
from restricting payloads so a value transfer is a genuine deep copy with no
35+
shared `Rc`.
36+
37+
1. **Type classification — `is_cross_isolate_safe(T)`** (`checks/local.rs`).
38+
Allowed: Copy scalars, and owned `struct`/`sum` values whose fields are all
39+
cross-isolate-safe. Denied: `List`/`Map`/`Set`, closures, any managed handle,
40+
resources, views, generic `T`. This is the reviewable essence: no `Rc` can
41+
cross, so a clone/move is alias-free.
42+
43+
2. **Surface** — a distinct mailbox API (e.g. `Mailbox<T>` + `Mailbox.pair()`,
44+
`Outbox.send(value: take T)`, `Inbox.recv()`), feature-gated, with
45+
`send` requiring `take` of a cross-isolate-safe `T`. Kept separate from the
46+
in-isolate `Channel<T>` so existing channel semantics are unchanged.
47+
48+
3. **Static enforcement** — at `Outbox.send`, infer the payload type and reject
49+
non-cross-isolate-safe `T` with a stable diagnostic (mirrors `take`
50+
validation). This is the primary defense and is fully testable without
51+
multi-threading.
52+
53+
4. **Execution** — run the two endpoints as cooperative tasks; transfer reuses the
54+
existing channel value-move (VM clones `VmValue`, Rust moves `T`). Because the
55+
payload has no `Rc`, this is alias-free on the shared heap — sound for the
56+
"single ownership / no shared managed handle" guarantee. Add a defensive
57+
runtime scan rejecting any `Rc`-bearing value (safety net for edge cases).
58+
59+
5. **Parity + tests**`tests/vm_eval_parity/async_concurrency.rs`: Copy payloads
60+
cross; managed payloads rejected at check time; ordering preserved; mixing with
61+
in-isolate channels.
62+
63+
## Larger, deferred option
64+
65+
True multi-thread / multi-heap isolates (`Arc<Mutex>`, `Send + Sync`, a
66+
thread-multiplexing scheduler) is a multi-quarter refactor that intentionally
67+
breaks the single-thread-simplicity design. Out of scope; the slice above delivers
68+
the spec's *static* guarantee without it.
69+
70+
## Decision
71+
72+
Recorded, not built. The static contract (step 1+3) is the high-value, sound,
73+
bounded core; steps 2/4/5 add the executable surface. Pick up when the mailbox
74+
surface is prioritized; until then the single-isolate model stands and managed
75+
handles simply cannot be sent anywhere.

docs/spec-todo.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,19 @@ model without reversing a review-first tenet. Ordered by readiness/value.
4646
review map already flags dynamic dispatch (`has_dynamic_protocol_dispatch`).
4747

4848
- [ ] **Cross-isolate message API (zero-copy transfer)** (§20.1-B, §20.2-3) —
49-
_large._ Typed send/receive channels between isolates; payloads are Copy/owned data
50-
or values moved with `take`; managed handles never cross. Single ownership enforced
51-
statically. Depends on the isolate model maturing first. _Touches:_ async/isolate
52-
runtime, type/effect checking for `take`-across-boundary, lowering + reg-VM.
49+
_blocked on foundational runtime work; design recorded._ Unlike the other three
50+
roadmap items (which were largely already built), this has **no foundation**: the
51+
runtime is strictly single-isolate (one cooperative-task heap; the channel is an
52+
explicit single-isolate `Rc<RefCell>` MPSC), so "managed handles never cross
53+
isolates" has no boundary to be enforced at yet — exactly why the spec gates it on
54+
"the isolate model maturing first." Faking it (cooperative tasks sharing a heap)
55+
would not be a real isolate boundary, so it is **not** implemented here.
56+
The smallest *sound* slice and the full feasibility analysis are recorded in
57+
[cross-isolate-design.md](cross-isolate-design.md): a static
58+
`is_cross_isolate_safe(T)` payload rule (Copy/owned, no managed handles) + a
59+
distinct `Mailbox<T>` surface over the cooperative scheduler (~1–2 weeks, holds
60+
parity). True multi-thread/multi-heap isolates are a separate multi-quarter
61+
refactor. Pick up when the mailbox surface is prioritized.
5362

5463
## Removed — non-goals (not deferred; deleted from the roadmap)
5564

0 commit comments

Comments
 (0)