<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body><div style="font-family: sans-serif;"><div class="markdown" style="white-space: normal;">
<p dir="auto">On 12 Dec 2023, at 14:41, Remi Forax wrote:</p>
</div><div class="plaintext" style="white-space: normal;"><blockquote style="margin: 0 0 5px; padding-left: 5px; border-left: 2px solid #777777; color: #777777;"><p dir="auto">… I don't want to be the guy implementing this :)
<br>
Your proposal is fighting against the physics of the VM, when you enter in an exception handler (a catch block)</p>
</blockquote></div>
<div class="markdown" style="white-space: normal;">
<p dir="auto">With my VM hat on I wrote something on another thread about<br>
this.  You can either split the switch or lift the expression<br>
to an Either record.</p>
<p dir="auto">So, I think that a switch with exception cases can be lowered by<br>
partitioning it into two switches, neither of which have<br>
exception cases. Then the two switches can be further lowered<br>
into an invokedynamic each, or something like that.  If the<br>
case logic needs to be processed as a whole by one BSM call,<br>
maybe the two indys share a condy which contains the<br>
static runtime analysis of the switch metadata.  Then each<br>
indy projects the data it needs out of the shared condy.<br>
Or, the expression result can be lifted to a 2-tuple of<br>
normal + exceptional results.  I’m just throwing out<br>
options here, obviously…</p>
<p dir="auto">So, this:</p>
<pre style="margin-left: 15px; margin-right: 15px; padding: 5px; background-color: #F7F7F7; border-radius: 5px 5px 5px 5px; overflow-x: auto; max-width: 90vw;"><code style="margin: 0; border-radius: 3px; background-color: #F7F7F7; padding: 0px;">… = switch (E0) {
  case P01 -> E01; case P02 -> E02; …
  case throws P10 -> E10; case throws P11 -> E11; …
};
</code></pre>
<p dir="auto">could lower to a two-switch shape like this:</p>
<pre style="margin-left: 15px; margin-right: 15px; padding: 5px; background-color: #F7F7F7; border-radius: 5px 5px 5px 5px; overflow-x: auto; max-width: 90vw;"><code style="margin: 0; border-radius: 3px; background-color: #F7F7F7; padding: 0px;">final $T2 $V2;  // temp to catch switch result
$L2: for (;;) {  // this block is breakable, maybe a one-execution for-loop
  final $T0 $V0;
  try {  // very narrow catch region, just for E0
    $V0 = E0;
    // normal exit falls through to normal (non-catching) cases (P01…)
  } catch ($T1 $V1) {  // $T1 is union of all exceptions covered by P10…
    // adjusted normal (non-catching) switch handles all catching cases (P10…)
    $V2 = switch ($V1) {
      case P10 -> E10; case P11 -> E11; …
    };
    break $L2;  // bytecode goto hops over non-throwing case logic
  }
  // normal (non-catching) switch handles normal cases (P01…)
  $V2 = switch ($V0) {
    case P01 -> E01; case P02 -> E02; …
  };
  break $L2;  // bytecode fallthrough
}
// $V2 is now live from one of the two breaks from $L2
… = $V2;
</code></pre>
<p dir="auto">The actual post-case statements (Enn) could be split between<br>
the two switches, or else merged into a third switch; the two<br>
initial switches would export bindings (as an Object) and<br>
also a small integer case number, which would be the selector<br>
to the third switch, rendered with a simple tableswitch bytecode.</p>
<p dir="auto">It is not trivial to support all switch features simultaneously.<br>
The third tableswitch seems (to me) to be a required tactic to<br>
support fall-through between cases.  It is probably overkill<br>
apart from that, although it is (to me as VM guy) appealing<br>
to funnel all the decision results through a tableswitch.</p>
<p dir="auto">Another way to think about this (there are many viable choices)<br>
is to lift the evaluation of the selector into a combination<br>
of two variables, a normal result and an exception, and then<br>
(somehow) run a single switch over the pair of values.</p>
<pre style="margin-left: 15px; margin-right: 15px; padding: 5px; background-color: #F7F7F7; border-radius: 5px 5px 5px 5px; overflow-x: auto; max-width: 90vw;"><code style="margin: 0; border-radius: 3px; background-color: #F7F7F7; padding: 0px;">final $T1 $V1 = null;  // temp to catch exceptional switch selector result
final $T2 $V2 = null;  // temp to catch normal switch selector result
try {  // very narrow catch region, just for E0
  $V2 = (E0);
} catch ($T1 $V1a) {  // $T1 is union of all exceptions covered by P10…
  $V1 = $V1a;
}
… = switch ($EITHER($V2, $V1)) {
  case $EITHER(P01, null) -> E01; …
  case $EITHER(null, P10) -> E10; …
}
</code></pre>
<p dir="auto">A Java programmer will need to “box” the two values together<br>
as an Either record (which I like to call an “ExBox”), but<br>
the javac engineer can probably get away with switching over<br>
an internal 2-tuple or Either type.  Maybe just a 2-array?</p>
<p dir="auto">I guess I won’t want to do the javac engineering either,<br>
but I do think the “lucky” engineer has multiple options.<br>
Fun stuff.</p>
<p dir="auto">— John</p>
<p dir="auto">P.S. If we ever get in-args into patterns it gets even more wooly,<br>
since those would be little expressions embedded in random places<br>
in the case patterns, and would be evaluated at unpredictable<br>
moments by the synthetic switch decision logic.  They probably<br>
need to be eta-converted (aka lambda-quoted) if they have any<br>
side-effects.  For more amusement on eta-conversion/lambda-quoting,<br>
you might like this:<br>
<a href="https://cr.openjdk.org/~jrose/jls/eta-abstraction-expr-quoting.html" style="color: #3983C4;">https://cr.openjdk.org/~jrose/jls/eta-abstraction-expr-quoting.html</a></p>

</div></div></body>

</html>