Effect cases in switch

John Rose john.r.rose at oracle.com
Thu Dec 14 07:16:54 UTC 2023


On 12 Dec 2023, at 14:41, Remi Forax wrote:

> … I don't want to be the guy implementing this :)
> Your proposal is fighting against the physics of the VM, when you 
> enter in an exception handler (a catch block)

With my VM hat on I wrote something on another thread about
this.  You can either split the switch or lift the expression
to an Either record.

So, I think that a switch with exception cases can be lowered by
partitioning it into two switches, neither of which have
exception cases. Then the two switches can be further lowered
into an invokedynamic each, or something like that.  If the
case logic needs to be processed as a whole by one BSM call,
maybe the two indys share a condy which contains the
static runtime analysis of the switch metadata.  Then each
indy projects the data it needs out of the shared condy.
Or, the expression result can be lifted to a 2-tuple of
normal + exceptional results.  I’m just throwing out
options here, obviously…

So, this:

```
… = switch (E0) {
   case P01 -> E01; case P02 -> E02; …
   case throws P10 -> E10; case throws P11 -> E11; …
};
```

could lower to a two-switch shape like this:

```
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;
```

The actual post-case statements (Enn) could be split between
the two switches, or else merged into a third switch; the two
initial switches would export bindings (as an Object) and
also a small integer case number, which would be the selector
to the third switch, rendered with a simple tableswitch bytecode.

It is not trivial to support all switch features simultaneously.
The third tableswitch seems (to me) to be a required tactic to
support fall-through between cases.  It is probably overkill
apart from that, although it is (to me as VM guy) appealing
to funnel all the decision results through a tableswitch.

Another way to think about this (there are many viable choices)
is to lift the evaluation of the selector into a combination
of two variables, a normal result and an exception, and then
(somehow) run a single switch over the pair of values.

```
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; …
}
```

A Java programmer will need to “box” the two values together
as an Either record (which I like to call an “ExBox”), but
the javac engineer can probably get away with switching over
an internal 2-tuple or Either type.  Maybe just a 2-array?

I guess I won’t want to do the javac engineering either,
but I do think the “lucky” engineer has multiple options.
Fun stuff.

— John

P.S. If we ever get in-args into patterns it gets even more wooly,
since those would be little expressions embedded in random places
in the case patterns, and would be evaluated at unpredictable
moments by the synthetic switch decision logic.  They probably
need to be eta-converted (aka lambda-quoted) if they have any
side-effects.  For more amusement on eta-conversion/lambda-quoting,
you might like this:
https://cr.openjdk.org/~jrose/jls/eta-abstraction-expr-quoting.html
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20231213/7c8b49e5/attachment.htm>


More information about the amber-spec-experts mailing list