gizmo
gizmo copied to clipboard
Shorter bytecode sequences to record array and Set values
In Quarkus, and in particular in ArC, there's the frequent need to generate code to record a Set
of Class constants; for example any created InjectableBean
will have a field private final Set types;
which needs to be initialized in the constructor.
The code being generated today is very verbose and generates intermediate variables for each individual element of the array; for example, focusing on the "type" use case we'd typically have:
Object[] var1 = new Object[2];
Class var2 = someClazz();
var1[0] = var2;
Class var3 = someClazz();
var1[1] = var3;
Set var4 = Set.of(var1);
this.types = var4;
as bytecode:
0: iconst_2
1: anewarray #2 // class java/lang/Object
4: astore_1
5: invokestatic #3 // Method someClazz:()Ljava/lang/Class;
8: astore_2
9: aload_1
10: iconst_0
11: aload_2
12: aastore
13: invokestatic #3 // Method someClazz:()Ljava/lang/Class;
16: astore_3
17: aload_1
18: iconst_1
19: aload_3
20: aastore
21: aload_1
22: invokestatic #4 // InterfaceMethod java/util/Set.of:([Ljava/lang/Object;)Ljava/util/Set;
25: astore 4
27: aload_0
28: aload 4
30: putfield #5 // Field types:Ljava/util/Set;
While this could have been expressed better as:
this.types = Set.of(someClazz(), someClazz());
0: aload_0
1: invokestatic #3 // Method someClazz:()Ljava/lang/Class;
4: invokestatic #3 // Method someClazz:()Ljava/lang/Class;
7: invokestatic #7 // InterfaceMethod java/util/Set.of:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/Set;
10: putfield #5 // Field types:Ljava/util/Set;
There's several minor benefits such ask bytecode size and the ability to skip allocating the array, but most importantly the lack of need for local variables would allow us to save space in the Constant Pool.
It would be nice to introduce some ad-hoc optimisations for these common patterns as required by ArC; we could simplify quite some code by just having specific support for recording immutable Sets and arrays.
I'm suggesting to add both optimisations:
ad-hoc optimized method for immutable, small Set creation
As made clear above, there's many benefits from this and set creation seems to be a very common need - in both ArC and likely other components too.
ad-hoc optimized method for storing arrays
This should help cover many other usecases; there are cases in which we need to store arrays that get non-trivial in size, and not all of them get folded into a Set. Having ad-hoc optimisations for arrays would give some more flexibility and address the largest consumers of space in the constant table.
Automatic elision of variable allocations
Ideally, but probably a much larger effort, it would be nice to see if gizmo could automatically chain directly consumed ResultHandler
(s) which are consumed only once so to not need local variables in such cases but use the stack.
That would have a more pervasive effect in removing many more variables, however seems to require some substantial design changes and I also suspect it wouldn't be able to generate the above optimal bytecode, so I'd focus on the Set and Array optimisations first.