<!-- BaNnErBlUrFlE-BoDy-start -->
<!-- Preheader Text : BEGIN -->
<div style="display:none !important;display:none;visibility:hidden;mso-hide:all;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;opacity:0;overflow:hidden;">
Hi Christian, Thanks, this is very helpful. On the ControlFlowException point: no, Protos does not need stack-frame capture for those bridged internal transfers. Guest Error is a separate lane and remains an AbstractTruffleException. The transfers</div>
<!-- Preheader Text : END -->

<!-- Email Banner : BEGIN -->
<div style="display:none !important;display:none;visibility:hidden;mso-hide:all;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;opacity:0;overflow:hidden;"></div>
<!-- Email Banner : END -->

<!-- BaNnErBlUrFlE-BoDy-end -->
<html><head><!-- BaNnErBlUrFlE-HeAdEr-start -->
<style>
  #pfptBanner93fmfra { all: revert !important; display: block !important;
    visibility: visible !important; opacity: 1 !important;
    background-color: #c2d4d4 !important;
    max-width: none !important; max-height: none !important }
  .pfptPrimaryButton93fmfra:hover, .pfptPrimaryButton93fmfra:focus {
    background-color: #a2b1b1 !important; }
  .pfptPrimaryButton93fmfra:active {
    background-color: #828e8e !important; }
  html:root, html:root>body { all: revert !important; display: block !important;
    visibility: visible !important; opacity: 1 !important; }
</style>

<!-- BaNnErBlUrFlE-HeAdEr-end -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head><body style='font-size: 10pt; font-family: Verdana,Geneva,sans-serif'>
<p>Hi Christian,</p>
<p>Thanks, this is very helpful.</p>
<p>On the ControlFlowException point: no, Protos does not need stack-frame capture for those bridged internal transfers.</p>
<p>Guest Error is a separate lane and remains an AbstractTruffleException. The transfers currently going through the Bytecode EH bridge are only non-local return and cooperative cancellation. In both cases we preserve the exact original ControlFlowException and unwrap it again at the owning call/resume boundary.</p>
<p>So the AbstractTruffleException envelope currently exists only to let those transfers cross Bytecode EH regions so that structured cleanup can run. We do not otherwise need guest exception stack information for it.</p>
<p>An opt-in mechanism allowing ControlFlowException to participate directly in the relevant Bytecode EH machinery would therefore fit Protos very well, and I would prefer that over the current envelope when available.</p>
<p>Your comments about continuation locals are also particularly useful. We will add explicit IGV inspection for:</p>
<p>- ordinary hot continuation-enabled roots that do not suspend;<br />- resumed Future.value() paths;<br />- ensure cleanup that itself suspends and resumes;<br />- continuation-local usage and live operand-stack values at resume points;<br />- whether continuation targets are being inlined as expected.</p>
<p>The cancellation point also matches our intent. Cancellation is cooperative and language-controlled rather than host-thread cancellation; it participates in structured unwind and cleanup, so we need to retain that semantic control.</p>
<p>I'll also join the #truffle Slack channel. As we complete the production cutover and get optimizing-runtime measurements, I'm happy to share any Bytecode DSL feedback or minimized cases that look useful.</p>
<p>Thanks again,</p>
<p>Guillermo Molina<br />Protos<br /><a href="https://github.com/guillermomolina/protos">https://github.com/guillermomolina/protos</a></p>
<p><br /></p>
<p id="reply-intro">On 2026-09-11 17:33, Christian Humer wrote:</p>
<blockquote type="cite" style="padding: 0 0.4em; border-left: #1010ff 2px solid; margin: 0">
<div id="replybody1" style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><span><br /></span>
<div>Hi Guillermo,</div>
<div> </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> </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> </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> </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> </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> </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/" target="_blank" rel="noopener noreferrer">https://www.graalvm.org/slack-invitation/</a></div>
<div> </div>
<div>Hope this was helpful.</div>
<div> </div>
<div>Christian</div>
<div><br />
<blockquote type="cite" style="padding: 0 0.4em; border-left: #1010ff 2px solid; margin: 0">
<div>On 11 Sep 2026, at 13:26, Guillermo Molina <protos@guillermomolina.com> wrote:</div>
<br class="v1Apple-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="v1Apple-tab-span" style="white-space: pre;"> </span>* source-backed closure calls composed across Bytecode roots;<br /> <span class="v1Apple-tab-span" style="white-space: pre;"> </span>* Task/Future suspension and resumption through ContinuationResult, <br />without replaying completed guest effects;<br /> <span class="v1Apple-tab-span" style="white-space: pre;"> </span>* non-local return, guest Error propagation/handlers, suspendible <br />ensure, cancellation and while;<br /> <span class="v1Apple-tab-span" style="white-space: pre;"> </span>* debugger scopes through TagTreeNode / NodeLibrary;<br /> <span class="v1Apple-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="v1Apple-tab-span" style="white-space: pre;"> </span>* normal guest values remain ordinary values;<br /> <span class="v1Apple-tab-span" style="white-space: pre;"> </span>* suspension is distinct from unwind and is represented by the <br />Bytecode continuation mechanism;<br /> <span class="v1Apple-tab-span" style="white-space: pre;"> </span>* guest Error remains a guest-exception lane;<br /> <span class="v1Apple-tab-span" style="white-space: pre;"> </span>* non-local return and cancellation are rare internal control-flow <br />transfers;<br /> <span class="v1Apple-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="v1Apple-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="v1Apple-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="v1Apple-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="v1Apple-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="v1Apple-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>
</div>
</blockquote>
<p><br /></p>

</body></html>