5

The extended switch expression in Java 14, the need of switch expression is unclear other than visual clarity for programmer/reviewer. Is it

  1. a different byte code implementation than older switch expression?
  2. any performance improvement in terms of execution over previous version?

Reference: https://www.techgeeknext.com/java/java14-features

JDK 14 version:

 int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;
};

JDK 14 -byte code

   0: iconst_1
   1: istore_1
   2: iload_1
   3: tableswitch   { // 1 to 7
                 1: 44
                 2: 44
                 3: 44
                 4: 49
                 5: 54
                 6: 54
                 7: 59
           default: 64
      }
  44: bipush        6
  46: goto          65
  49: bipush        7
  51: goto          65
  54: bipush        8
  56: goto          65
  59: bipush        9
  61: goto          65
  64: iconst_0
  65: istore_2
  66: return

JDK - 10 Code

int numLetters;
int day = 1;
switch (day) {
  case 1:
  case 2:
  case 3:
    numLetters = 6;
    break;
  case 4:
    numLetters = 7;
    break;
  case 5:
  case 6:
    numLetters = 8;
    break;
  case 7:
    numLetters = 9;
    break;
  default:
    numLetters = 0;
}

JDK - 10 Byte code

   0: iconst_1
   1: istore_2
   2: iload_2
   3: tableswitch   { // 1 to 7
                 1: 44
                 2: 44
                 3: 44
                 4: 50
                 5: 56
                 6: 56
                 7: 62
           default: 68
      }
  44: bipush        6
  46: istore_1
  47: goto          70
  50: bipush        7
  52: istore_1
  53: goto          70
  56: bipush        8
  58: istore_1
  59: goto          70
  62: bipush        9
  64: istore_1
  65: goto          70
  68: iconst_0
  69: istore_1
  70: return

There are no major difference for primitives, apart from local assignments within blocks has reduced JIT instructions.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Jatish
  • 352
  • 1
  • 2
  • 10
  • What did you try to find it out yourself? – Ronald Jan 15 '20 at 09:47
  • The JEP: https://openjdk.java.net/jeps/361 – Jatish Jan 15 '20 at 09:51
  • 1
    @Ronald I have edited the details in the question, the things I have researched on. – Jatish Jan 15 '20 at 10:17
  • 1
    Well, with the edit you've already shown yourself that the bytecode is slightly different. From the performance point of view there's not that much difference. In Java10 the number of executed statements is 8 (0, 1, 2, 3, 44, 46, 47, 70) in Java14 it's only 7 (0, 1, 2, 3, 44, 46, 66). It's likely that the tableswitch (3) statement is the expensive one. Hence I'd expect a performance gain of a few percent. (Execute both variants 100,000 times in a loop and measure the time). – Ronald Jan 15 '20 at 10:25
  • There are not major performance improvements when I am using primitive (int) here and choice is static - value for `day = 1`. I have executed the loop `Two billion+ times`. The execution time are as JDK-14 - 3317.8 μs and JDK 10 - 3343.200 μs – Jatish Jan 15 '20 at 10:36
  • The case gets interesting when last option is valid, (does mean day = 7). The execution time are as JDK 14 - 3689.400 μs and JDK 10 - 2642.000 μs . So, which one performs better? – Jatish Jan 15 '20 at 10:43
  • The huge difference in the second test (which was an excellent idea) is either caused by a new implementation of the tableswitch statement, or by something disturbing the measurement. If the results are repeatable, I'd say that something went wrong in the new implementation. The first result matches my expectation (<1% gain in performance, most likely because of the eliminated statement and maybe worse than expected because of the assumed new implementation of the tableswitch). It's not clear why JDK 10 performs so much better for day 7. But it might be due to a different order of evaluation. – Ronald Jan 15 '20 at 11:15
  • @Ronald, thank you for the nice explanation. I took it further (As Java Integers are cached but not int), so I have used valued more than caching limit with multiple execution on the same program with last option as successful evaluation. The execution results are as `JDK - 14 - 4335.900 μs (avg) and JDK 10 - 3562.400 (avg.)` – Jatish Jan 15 '20 at 11:24

1 Answers1

4

Like with switch over String, the bytecode didn’t change and there was no need to.

While the bytecode had been designed specifically to serve as a target for compiling Java source code, it’s not restricted in the same way. See also Bytecode features not available in the Java language

The switch expression exploits a feature formerly not used by ordinary Java code, but surely used by automatic code generators or compilers for other programming languages targeting the JVM, the possibility to push values to the operand stack in the different branches of the switch cases, to be used after the merge point. For the good old switch statement you always had to store the value into a local variable and load it after the merge point.

〈Another feature not exploited by ordinary Java code, but which works smoothly with Java bytecode, is to (ab)use a switch instruction to produce fancy loops, by just having target location(s) before the switch instruction. Who knows whether some source code feature will ever exploit that in a future language version…〉

But whether an intermediate local variable is used or not, should not matter much. After the optimizer converted the code into the SSA form, all transfers between local variables and the operand stack are eliminated even before the other code transformations and optimizations apply.

This doesn’t preclude surprising performance differences caused by subtle changes to a switch instruction in a particular implementation (version).

Holger
  • 285,553
  • 42
  • 434
  • 765