[graalvm-dev] [External] : Truffle Bytecode DSL production cutover with continuations and structured control flow
protos at guillermomolina.com
protos at guillermomolina.com
Fri Sep 11 11:26:31 UTC 2026
Hi,
I'm Guillermo Adrián Molina, author of Protos, a prototype-based
language implemented on Truffle 25.3.4.1.
I originally intended to ask about how to represent dynamic guest
control flow around Bytecode DSL continuations, but the implementation
has progressed quite a bit since then, so I thought a more useful
question would be about the final production cutover and any pitfalls we
may be missing.
Protos is migrating from an AST-based cooperative replay mechanism to a
Bytecode DSL backend.
The Bytecode path now supports:
* source-backed closure calls composed across Bytecode roots;
* Task/Future suspension and resumption through ContinuationResult,
without replaying completed guest effects;
* non-local return, guest Error propagation/handlers, suspendible
ensure, cancellation and while;
* debugger scopes through TagTreeNode / NodeLibrary;
* StatementTag/CallTag source identity and logical BytecodeLocation
preservation across suspension/resume.
The control-flow model we ended up with is:
* normal guest values remain ordinary values;
* suspension is distinct from unwind and is represented by the
Bytecode continuation mechanism;
* guest Error remains a guest-exception lane;
* non-local return and cancellation are rare internal control-flow
transfers;
* a narrow interceptControlFlowException bridge allows those internal
transfers to cross Bytecode EH regions so that structured cleanup can
run, while retaining the exact original transfer;
* pending transfers live in resumable Bytecode/frame state while
cleanup executes, including when cleanup itself suspends;
* there is no replay tape, global continuation registry, semantic
ThreadLocal, or parked thread on the Bytecode path.
At this point the remaining work is mostly production cutover: complete
a couple of hosting/native boundaries, switch normal
TruffleLanguage.parse() execution to the Bytecode backend, retire the
old replay path, and then enable/measure the optimizing Truffle runtime
in ordinary execution.
I would be interested in feedback on three points:
* Does the separation above -- Bytecode continuations for suspension,
structured Bytecode EH/finally for unwind, and a narrow
ControlFlowException bridge for internal transfers -- match the intended
direction of the Bytecode DSL, or is there another pattern you would
recommend for a production language?
* Are there known caveats when making a continuation-enabled Bytecode
DSL root the normal production backend, particularly for runtime
compilation / partial evaluation? For example, does enabling yield have
meaningful cost for roots that never actually suspend?
* Are there specific diagnostics or invariants you recommend checking
during the final AST-to-Bytecode cutover to make sure resumed paths,
structured control flow, source metadata and runtime compilation remain
optimization-friendly?
The project is guillermomolina/protos on GitHub if concrete
implementation details are useful.
Thanks,
Guillermo Adrián Molina
Protos
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://oss.oracle.com/pipermail/graalvm-dev/attachments/20260911/90d5f0f2/attachment.htm>
More information about the GraalVM-Dev
mailing list