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