<html aria-label="message body">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">
<span><br>
</span>
<div>Hi Guillermo,</div>
<div><br>
</div>
<div>Always glad to learn about a new bytecode DSL user. If you also have some general feedback, that is always appreciated. </div>
<div><br>
</div>
<div>The separation between suspension and unwinding sounds sensible. Generally, the intended direction is to avoid ControlFlowException for ordinary control flow: it was primarily a workaround for AST interpreters, whereas bytecode can usually express that
control flow directly. From you docs I read that you explicitly decided to not use Truffle’s safe point mechanism for cancellation. That can be a sensible decision if you want your users to recover from cancellation. </div>
<div><br>
</div>
<div>Your cross-call non-local returns are one of the rarer cases where CFE can still make sense. Desugaring them into ordinary returns would require propagating an explicit transfer through intermediate calls. The conversion to AbstractTruffleException to
run ensure cleanup is not ideal, though we should probably support CFEs directly in the relevant Bytecode exception-handling machinery as an opt-in. This would allow you handle CFEs like truffle exceptions but don’t pay the cost for capturing stack frames.
Or is this something you need anyway?</div>
<div><br>
</div>
<div>For continuation-enabled roots, the main performance caveat is that operand-stack values are virtualized after runtime compilation, but continuation locals are not, making local accesses slower. Entering a continuation with many live stack values also
has a cost to bring those values into compiled execution and virtualize them. That of course only applies if the continuation target is not inlined.</div>
<div><br>
</div>
<div>Getting a continuation-enabled bytecode interpreter right for partial evaluation is tricky, but the Bytecode DSL handles that machinery. So no problems are expected here. I would still inspect IGV graphs, particularly for resumed paths and cleanup that
itself suspends to double check everything is as expected.</div>
<div><br>
</div>
<div>You’re also welcome to also join the community Slack to discuss this further directly. (#truffle channel)</div>
<div><a href="https://www.graalvm.org/slack-invitation/">https://www.graalvm.org/slack-invitation/</a></div>
<div><br>
</div>
<div>Hope this was helpful.</div>
<div><br>
</div>
<div>Christian</div>
<div><br>
<blockquote type="cite">
<div>On 11 Sep 2026, at 13:26, Guillermo Molina <protos@guillermomolina.com> wrote:</div>
<br class="Apple-interchange-newline">
<div>
<div>Hi,<br>
<br>
I'm Guillermo Adri?n Molina, author of Protos, a prototype-based <br>
language implemented on Truffle 25.3.4.1.<br>
<br>
I originally intended to ask about how to represent dynamic guest <br>
control flow around Bytecode DSL continuations, but the implementation <br>
has progressed quite a bit since then, so I thought a more useful <br>
question would be about the final production cutover and any pitfalls we <br>
may be missing.<br>
<br>
Protos is migrating from an AST-based cooperative replay mechanism to a <br>
Bytecode DSL backend.<br>
<br>
The Bytecode path now supports:<br>
<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* source-backed closure calls composed across Bytecode roots;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* Task/Future suspension and resumption through ContinuationResult,
<br>
without replaying completed guest effects;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* non-local return, guest Error propagation/handlers, suspendible
<br>
ensure, cancellation and while;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* debugger scopes through TagTreeNode / NodeLibrary;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* StatementTag/CallTag source identity and logical BytecodeLocation
<br>
preservation across suspension/resume.<br>
<br>
The control-flow model we ended up with is:<br>
<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* normal guest values remain ordinary values;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* suspension is distinct from unwind and is represented by the
<br>
Bytecode continuation mechanism;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* guest Error remains a guest-exception lane;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* non-local return and cancellation are rare internal control-flow
<br>
transfers;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* a narrow interceptControlFlowException bridge allows those internal
<br>
transfers to cross Bytecode EH regions so that structured cleanup can <br>
run, while retaining the exact original transfer;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* pending transfers live in resumable Bytecode/frame state while
<br>
cleanup executes, including when cleanup itself suspends;<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* there is no replay tape, global continuation registry, semantic
<br>
ThreadLocal, or parked thread on the Bytecode path.<br>
<br>
At this point the remaining work is mostly production cutover: complete <br>
a couple of hosting/native boundaries, switch normal <br>
TruffleLanguage.parse() execution to the Bytecode backend, retire the <br>
old replay path, and then enable/measure the optimizing Truffle runtime <br>
in ordinary execution.<br>
<br>
I would be interested in feedback on three points:<br>
<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* Does the separation above -- Bytecode continuations for suspension,
<br>
structured Bytecode EH/finally for unwind, and a narrow <br>
ControlFlowException bridge for internal transfers -- match the intended <br>
direction of the Bytecode DSL, or is there another pattern you would <br>
recommend for a production language?<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* Are there known caveats when making a continuation-enabled Bytecode
<br>
DSL root the normal production backend, particularly for runtime <br>
compilation / partial evaluation? For example, does enabling yield have <br>
meaningful cost for roots that never actually suspend?<br>
<span class="Apple-tab-span" style="white-space:pre"> </span>* Are there specific diagnostics or invariants you recommend checking
<br>
during the final AST-to-Bytecode cutover to make sure resumed paths, <br>
structured control flow, source metadata and runtime compilation remain <br>
optimization-friendly?<br>
<br>
The project is guillermomolina/protos on GitHub if concrete <br>
implementation details are useful.<br>
<br>
Thanks,<br>
<br>
Guillermo Adri?n Molina<br>
Protos<br>
-------------- next part --------------<br>
An HTML attachment was scrubbed...<br>
URL: <http://oss.oracle.com/pipermail/graalvm-dev/attachments/20260911/90d5f0f2/attachment.htm><br>
<br>
</div>
</div>
</blockquote>
</div>
<br>
</body>
</html>