<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <font size="4"><font face="monospace">I'm still a little
        uncomfortable at the BiPredicate approach, for two reasons:<br>
        <br>
         - It's more "magic" than having the user explicitly say "unroll
        the finally here"<br>
         - I'm not convinced the usability is better<br>
        <br>
        You shared the following example:<br>
        <br>
        ```<br>
                try {<br>
                    try {<br>
                        System.out.println("INNER TRY START");<br>
                        String s = args[0];<br>
                        if (s.length() < 10) {<br>
                            [0]<br>
                            return -1;<br>
                        }<br>
                        System.out.println("INNER TRY END");<br>
                        // Exit<br>
      </font></font><font size="4"><font face="monospace"><font size="4"><font face="monospace">                // [1]<br>
          </font></font>            } catch (RuntimeException e) {<br>
                        System.out.println("INNER RUNTIME EXCEPTION");<br>
                        // [2]<br>
                        throw e;<br>
                    } finally {<br>
                        System.out.println("INNER FINALLY");<br>
                    }<br>
                    System.out.println("OUTER TRY");<br>
      </font></font><font size="4"><font face="monospace"><font size="4"><font face="monospace">            // [3]<br>
          </font></font>            // Exit<br>
                } catch (RuntimeException e) {<br>
                    System.out.println("OUTER RUNTIME EXCEPTION");<br>
      </font></font><font size="4"><font face="monospace"><font size="4"><font face="monospace">            // [4]<br>
          </font></font>            throw e;<br>
                } finally {<br>
                    System.out.println("OUTER FINALLY");<br>
                }<br>
        ```<br>
        <br>
        I must admit that at first look, I don't know where the finally
        blocks have to be inserted, but looking at the javap output, it
        looks like:<br>
        <br>
         - [0] -- inner and outer finally<br>
         - [1] -- inner finally (then falls out)<br>
         - [2] -- nothing (handled as stack unwinds by any handler)<br>
         - [3] -- outer<br>
         - [4] -- nothing (handled by any handler)<br>
        <br>
        Plus a pair of "any" handlers, the first of which does the inner
        finally, the second does the outer, and the second is in scope
        for the first.  Whew!  <br>
        <br>
        There's several groups of questions here.  <br>
        <br>
        One is "what does the user know, and when do they know it."  A
        block like the above might not be generated with pure try-catch
        builder; it might be that the inner block comes from the class
        being adapted, and the outer block is being added by a
        transform.  So the user may not even know about the inner
        try-catch block!  In this case, we would have a problem at [0]
        only, where the code being adapted has already inlined the inner
        finally, but we would have to realize that prior to a return,
        we'd have to also unroll the inner finally.  <br>
        <br>
        Which exposes problem #1 -- it's not just branch instructions
        that the BiPredicate would have to examine, its also returns
        (unless you are treating these unconditionally as needing
        finally unrolling.)  <br>
        <br>
        Setting that aside, the real question is whether a branch target
        that is a branch target is internal to the try+catch blocks, or
        "outside".  Which we would handle by examining the label.  But
        the usability of this is not so great, because the label may not
        have been bound yet, and so all the user can do is compare it
        for identity with the N labels known to be in the block.  That
        sounds like kind of a pain for the user to implement.<br>
        <br>
        So here's another possible thought: what if BlockBuilder could
        dispense labels, as well as dispensing blocks, and could then
        keep track of containment?  So if you are branching to a label
        *outside this block builder* (including returning), we'd inline
        the finally at that point.  (With nested block builders, we'd
        have to keep track of which BBs belonged to other BBs, but we
        already do this.)  <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
      </font></font>
    <div class="moz-cite-prefix">On 8/24/2022 4:51 PM, Paul Sandoz
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:D87BEBCA-8FC4-450A-8ED0-E1D14620B8B2@oracle.com">
      
      Here’s an update:
      <div class=""><br class="">
      </div>
      <div class=""><a href="https://github.com/openjdk/jdk-sandbox/compare/classfile-api-branch...PaulSandoz:jdk-sandbox:try-catch-finally-builder?expand=1" class="moz-txt-link-freetext" moz-do-not-send="true">https://github.com/openjdk/jdk-sandbox/compare/classfile-api-branch...PaulSandoz:jdk-sandbox:try-catch-finally-builder?expand=1</a></div>
      <div class="">
        <pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.8pt;" class=""><span style="color:#0033b3;" class="">sealed interface </span><span style="color:#000000;" class="">CatchFinallyBuilder </span><span style="color:#0033b3;" class="">permits </span><span style="color:#000000;" class="">CatchFinallyBuilderImpl </span>{
    <span style="color:#000000;" class="">CatchFinallyBuilder </span><span style="color:#00627a;" class="">catching</span>(<span style="color:#000000;" class="">ClassDesc </span>exceptionType, <span style="color:#000000;" class="">Consumer</span><<span style="color:#000000;" class="">BlockCodeBuilder</span>> catchHandler);

    <span style="color:#0033b3;" class="">default void </span><span style="color:#00627a;" class="">finally_</span>(<span style="color:#000000;" class="">Consumer</span><<span style="color:#000000;" class="">BlockCodeBuilder</span>> finallyHandler) {
        finally_(<span style="color:#871094;font-style:italic;" class="">INLINE_FINALLY_ON_BREAK</span>, finallyHandler);
    }

    <span style="color:#0033b3;" class="">void </span><span style="color:#00627a;" class="">finally_</span>(<span style="color:#000000;" class="">BiPredicate</span><<span style="color:#000000;" class="">BlockCodeBuilder</span>, <span style="color:#000000;" class="">BranchInstruction</span>> inlineFinallyTest,
                  <span style="color:#000000;" class="">Consumer</span><<span style="color:#000000;" class="">BlockCodeBuilder</span>> finallyHandler);

    <span style="color:#000000;" class="">BiPredicate</span><<span style="color:#000000;" class="">BlockCodeBuilder</span>, <span style="color:#000000;" class="">BranchInstruction</span>> <span style="color:#871094;font-style:italic;" class="">INLINE_FINALLY_ON_BREAK </span>=
            (b, i) -> b.breakLabel() == i.target();
}
</pre>
        <div class="">The terminal finally_ builder method accepts an
          optional predicate.</div>
        <div class=""><br class="">
        </div>
        <div class="">Paul. </div>
        <br class="">
        <blockquote type="cite" class="">On Aug 24, 2022, at 10:57 AM,
          Paul Sandoz <<a href="mailto:paul.sandoz@oracle.com" class="moz-txt-link-freetext" moz-do-not-send="true">paul.sandoz@oracle.com</a>>
          wrote:<br class="">
          <br class="">
          Or, alternatively, the user can provide an optional
          BiPredicate<BlockCodeBuilder, BranchInstruction>, which
          is called for every branch instruction of a try or catch
          block, and returns true if the branches target is known to
          exit the block and therefore the finally blocks need to be
          inlined before it. The default implementation is specified to
          behave as it does in the prototype, and can be composed.<br class="">
          <br class="">
          That seems to give the developer the control they need without
          explicitly emitting finally blocks, which could get more
          complex when nesting trying builders.<br class="">
          <br class="">
          Paul.<br class="">
          <br class="">
          <blockquote type="cite" class="">On Aug 23, 2022, at 6:12 PM,
            Brian Goetz <<a href="mailto:brian.goetz@oracle.com" class="moz-txt-link-freetext" moz-do-not-send="true">brian.goetz@oracle.com</a>>
            wrote:<br class="">
            <br class="">
            Maybe the TCB should have an â€œemit finally” method that
            causes the finally lambda to be called at that point?<br class="">
            <br class="">
            Sent from my MacBook Wheel<br class="">
            <br class="">
            <blockquote type="cite" class="">On Aug 23, 2022, at 6:39
              PM, Paul Sandoz <<a href="mailto:paul.sandoz@oracle.com" class="moz-txt-link-freetext" moz-do-not-send="true">paul.sandoz@oracle.com</a>>
              wrote:<br class="">
              <br class="">
              ï»¿Hi,<br class="">
              <br class="">
              Here’s a prototype of a try/catch/finally builder (that
              should replace the current approach):<br class="">
              <br class="">
              <a href="https://github.com/openjdk/jdk-sandbox/compare/classfile-api-branch...PaulSandoz:jdk-sandbox:try-catch-finally-builder?expand=1" class="moz-txt-link-freetext" moz-do-not-send="true">https://github.com/openjdk/jdk-sandbox/compare/classfile-api-branch...PaulSandoz:jdk-sandbox:try-catch-finally-builder?expand=1</a><br class="">
              <br class="">
              So far it all seems to work and produces correct code for
              nested building, generating similar code as the source
              compiler produces.<br class="">
              <br class="">
              I need to do more thorough testing and commit unit tests.<br class="">
              <br class="">
              â€”<br class="">
              <br class="">
              One challenge is determining when a block exits. A
              branching instruction that exits the block should result
              in inlining of the finally code before the instruction,
              but it's hard to precisely determine if the branch target
              is within or outside of the block. At the moment I hard
              code to checking if the target is the break label of the
              block, otherwise it is assumed the branch does not exit
              the block. I don’t think this is generally decidable
              unless all block instructions are first buffered.<br class="">
              <br class="">
              Paul.<br class="">
            </blockquote>
          </blockquote>
          <br class="">
        </blockquote>
        <br class="">
      </div>
    </blockquote>
    <br>
  </body>
</html>