diff --git a/DISCUSS.md b/DISCUSS.md index bc6b824..b676fdb 100644 --- a/DISCUSS.md +++ b/DISCUSS.md @@ -486,3 +486,53 @@ embedding OCaml 5.2 — and the multicore runtime means the most likely obstacle **Order of work:** answer the embedding questions above with a spike, not a rewrite. If OCaml embeds acceptably, item 11 is buildable and no port is needed. Self-hosting stays a long-term ambition rather than a prerequisite. + +## 13. The two questions are independent, and the order matters + +The end of the session, and the clearest statement of what is actually being decided. Read this before items 10, 11 +and 12, which were each written mid-argument. + +**Two separate decisions, repeatedly conflated in conversation:** + +1. **One process or two** — whether the compiler runs inside the program's process. This is about *transport*: how + compiled code and inspection data move between the compiler and the running program. +2. **How machine code is produced and installed** — the current `llc` + `ld` + `dlopen`, libLLVM's in-process JIT + (ORC), or a hand-written lowering. This is about *code generation*. + +Neither implies the other. A hand-written backend removes `llc` and `ld` (about 21ms of a 35ms redefinition) and +leaves the transport. Merging the processes removes the transport and leaves code generation exactly as it is. +**Merging is the larger prize.** + +**And there is a third option for question 2 that keeps getting lost: change nothing.** In one process you can still +write a `.so` and `dlopen` it. You lose nothing that works today, and you still delete the socket, the wire protocol, +the 4K result cap, the seqlock, the snapshot copying, the render-thunk-per-inspection, and `flan reload` paying process +startup every time. + +**So the order is:** + +1. **Spike the embedding** (item 12). OCaml 5.2's multicore runtime removes the objection that would have been fatal. + If it embeds acceptably, everything below is reachable. +2. **Merge the processes**, keeping the existing code path. Biggest win, no new dependency, deletes the most + machinery. +3. **Measure what is left.** With transport gone, a redefinition is whatever code generation costs. That may simply be + fine. +4. **Then decide the backend, on evidence.** libLLVM's JIT means linking the library `plan.org` rejected — for + reasons that were right at the time, when the JIT was worth ~13ms and nothing else. In one process it is worth the + file, the load, the unbounded accumulation *and* cheap evaluation of arbitrary real code, which the author has since + named as a first-class want. The cost is also more bounded than "breaks routinely" suggests: the bindings track + LLVM major versions, so it is a pin you own and upgrade deliberately. + + A hand-written lowering buys the same speed plus no dependency and a disassembler you own, at the cost of an + instruction selector per architecture, maintained forever. The drift risk is real but testable — the `@sanitize` + alias already builds 28 programs twice and compares output and exit status, which is exactly the harness two + backends would need. + +**The principle to keep:** the original decision was made on a measurement and it held up for months. Make this one the +same way — merge first, measure, then choose. Do not pre-empt step 4 at step 1. + +**Also settled in passing:** a release build can include the compiler and server and simply not be connected to, the +way an SBCL executable can. The dev/release split is a build flag, not an architectural constraint. + +**And one correction to keep:** OCaml's own wasm support is irrelevant to any of this. OCaml is the compiler's +implementation language; Flan programs reach wasm through LLVM. The two only meet if the *compiler* should run in a +browser, which is not a goal.