Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8318060

Pattern matching for switch (JEP 420) generates sub-optimal bytecode

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      CPU: Intel I7-9700K, 8 cores @ 4.9 GHz
      Memory: 16 GB
      OS: Zorin OS 16.3, x86_64 (Based on Debian Linux)
      Java Runtime: OpenJDK Runtime Environment (build 21+45-2513), 64 bit
      Java Compiler: javac 21 (Same distribution as Java Runtime mentioned above)

      A DESCRIPTION OF THE PROBLEM :
      Javac's compilation of switch statements using `instanceof`-like patterns generates sub-optimal bytecode.
      For example:
      class Hello {
      void foo() {
      Object o = "hello";
      switch(o) {
      case String s -> System.out.println(s);
      case Integer i -> System.out.printf("int %s", i);
      default -> System.out.println("huh");
      }
      }
      }
      Javac adds this header to the top of the resulting switch case:
      ```
       3: aload_1 ; Switch input, this is the `o` variable
       4: dup
       5: invokestatic #9 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
       8: pop
       9: astore_2
      10: iconst_0
      11: istore_3
      12: aload_2
      13: iload_3
      14: invokedynamic #15, 0 // InvokeDynamic #0:typeSwitch:(Ljava/lang/Object;I)I
      ```
      This header wastes 2 entire local slots, and does a lot of unnecessary stack operations for what is basically just an invokedynamic call, with one argument wrapped in an Objects.requireNonNull.
      A java representation could be written like such:
      ```
      Objects.requireNonNull(o);
      Object oCpy = o;
      int startIdx = 0;
      switch((int) SwitchBootstraps.typeSwitch(...).getTarget().invoke(oCpy, startIdx)) {
        // ...
      }
      Instead, bytecode like this could be generated:
      ```
      aload_1
      invokestatic java/util/Objects.requireNonNull(Ljava/lang/Object;)Ljava/lang/Object;
      iconst_0
      invokedynamic java/lang/runtime/SwitchBootstraps.typeSwitch(...)... ; Continue with standard procedure
      ```
      The above bytecode would both save 2 local slots, and save 6 instructions.


            jlahoda Jan Lahoda
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: