Possibly inefficient code gen of instanceof patterns

Claes Redestad claes.redestad at oracle.com
Thu Jan 28 14:14:36 UTC 2021


I haven't, no. Increasing bytecode size like this has historically
been shown to cause issues with some inlining heuristics that
(unfortunately) take bytecode size into consideration.

/Claes

On 2021-01-28 15:08, Volker Simonis wrote:
> I understand that this question is about javac but nevertheless it would 
> be interesting to know if and if yes how your little change affects the 
> C2 generated assembly code. Have you checked that?
> 
> Claes Redestad <claes.redestad at oracle.com 
> <mailto:claes.redestad at oracle.com>> schrieb am Do., 28. Jan. 2021, 14:59:
> 
>     Hi,
> 
>     as an experiment, I changed some code to use instanceof pattern
>     matching to see if there's any effect on the generated code.
> 
>     Consider j.l.i.BootstrapMethodInvoker.invoke, which I changed from:
> 
>           private static Object invoke(MethodHandle bootstrapMethod, Lookup
>     caller,
>                                        String name, Object type) throws
>     Throwable {
>               if (type instanceof Class) {
>                   return bootstrapMethod.invoke(caller, name, (Class)type);
>               } else {
>                   return bootstrapMethod.invoke(caller, name,
>     (MethodType)type);
>               }
>           }
> 
>     .. to:
> 
>           private static Object invoke(MethodHandle bootstrapMethod, Lookup
>     caller,
>                                        String name, Object type) throws
>     Throwable {
>               if (type instanceof Class c) {
>                   return bootstrapMethod.invoke(caller, name, c);
>               } else {
>                   return bootstrapMethod.invoke(caller, name,
>     (MethodType)type);
>               }
>           }
> 
>     This seem to grow the bytecode size ever so slightly. Looking at the
>     javap output it seems some of that might be redundant and possibly
>     fixable:
> 
>         private static java.lang.Object
>     invoke(java.lang.invoke.MethodHandle,
>     java.lang.invoke.MethodHandles$Lookup, java.lang.String,
>     java.lang.Object) throws java.lang.Throwable;
>           descriptor:
>     (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
>           flags: (0x000a) ACC_PRIVATE, ACC_STATIC
>           Code:
>             stack=4, locals=6, args_size=4
>                0: aload_3
>                1: astore        5
>                3: aload         5
>                5: instanceof    #46                 // class java/lang/Class
>                8: ifeq          27
>               11: aload         5
>               13: checkcast     #46                 // class java/lang/Class
>               16: astore        4
>               18: aload_0
>               19: aload_1
>               20: aload_2
>               21: aload         4
>               23: invokevirtual #169                // Method
>     java/lang/invoke/MethodHandle.invoke:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
>               26: areturn
>               27: aload_0
>               28: aload_1
>               29: aload_2
>               30: aload_3
>               31: checkcast     #61                 // class
>     java/lang/invoke/MethodType
>               34: invokevirtual #172                // Method
>     java/lang/invoke/MethodHandle.invoke:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object;
>               37: areturn
>             LineNumberTable:
>               line 226: 0
>               line 227: 18
>               line 229: 27
>             LocalVariableTable:
>               Start  Length  Slot  Name   Signature
>                  18       9     4     c   Ljava/lang/Class;
>                   0      38     0 bootstrapMethod
>     Ljava/lang/invoke/MethodHandle;
>                   0      38     1 caller
>     Ljava/lang/invoke/MethodHandles$Lookup;
>                   0      38     2  name   Ljava/lang/String;
>                   0      38     3  type   Ljava/lang/Object;
>             StackMapTable: number_of_entries = 1
>               frame_type = 27 /* same */
>           Exceptions:
>             throws java.lang.Throwable
> 
>     - The storing and loading of the type argument into slot 5 seem
>     completely redundant: couldn't we load slot 3 in each place that
>     now loads slot 5?
> 
>     - Storing c into a new slot 4 also seem unfortunate, but is more
>     understandable (I guess this is a limitation of the LVT not allowing
>     overlapping a new variable with a new type into the same slot?)
> 
>     - It's also unfortunate that the checkcast now bubbles up so that the
>     result has to be stored and loaded again, but I guess pushing the
>     checkcast down to just before the invokevirtual as in the other
>     branch would go against some specification.
> 
>     My gut feeling - without knowing much about javac - is that at least
>     the use of a temporary slot (5) could be optimized away here.
> 
>     WDYT?
> 
>     For reference the baseline method without the pattern matching
>     compiles to this:
> 
>         private static java.lang.Object
>     invoke(java.lang.invoke.MethodHandle,
>     java.lang.invoke.MethodHandles$Lookup, java.lang.String,
>     java.lang.Object) throws java.lang.Throwable;
>           descriptor:
>     (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
>           flags: (0x000a) ACC_PRIVATE, ACC_STATIC
>           Code:
>             stack=4, locals=4, args_size=4
>                0: aload_3
>                1: instanceof    #46                 // class java/lang/Class
>                4: ifeq          18
>                7: aload_0
>                8: aload_1
>                9: aload_2
>               10: aload_3
>               11: checkcast     #46                 // class java/lang/Class
>               14: invokevirtual #169                // Method
>     java/lang/invoke/MethodHandle.invoke:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
>               17: areturn
>               18: aload_0
>               19: aload_1
>               20: aload_2
>               21: aload_3
>               22: checkcast     #61                 // class
>     java/lang/invoke/MethodType
>               25: invokevirtual #172                // Method
>     java/lang/invoke/MethodHandle.invoke:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object;
>               28: areturn
>             LineNumberTable:
>               line 226: 0
>               line 227: 7
>               line 229: 18
>             LocalVariableTable:
>               Start  Length  Slot  Name   Signature
>                   0      29     0 bootstrapMethod
>     Ljava/lang/invoke/MethodHandle;
>                   0      29     1 caller
>     Ljava/lang/invoke/MethodHandles$Lookup;
>                   0      29     2  name   Ljava/lang/String;
>                   0      29     3  type   Ljava/lang/Object;
>             StackMapTable: number_of_entries = 1
>               frame_type = 18 /* same */
>           Exceptions:
>             throws java.lang.Throwable
> 
>     Thanks!
> 
>     /Claes
> 


More information about the compiler-dev mailing list