Either the presentation was not entirely accurate, or you did not understand it.
In fact, the JVM can have built-in non-static methods, even with varargs. Moreover, it can exclude allocation of the corresponding Object[] array in certain cases. Unfortunately, it does not do this when the vararg method iterates through the array using a for loop.
I did the following JMH to test the theory and run it using the GC profiler ( -prof gc ).
package bench; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.infra.Blackhole; public class VarArgs { @Benchmark public void inlineNonStatic(Blackhole bh) { inlineNonStaticVA(bh, "foo", 4, new Object()); } @Benchmark public void inlineStatic(Blackhole bh) { inlineStaticVA(bh, "foo", 4, new Object()); } @Benchmark public void loopNonStatic(Blackhole bh) { loopNonStaticVA(bh, "foo", 4, new Object()); } @Benchmark public void loopStatic(Blackhole bh) { loopStaticVA(bh, "foo", 4, new Object()); } public void inlineNonStaticVA(Blackhole bh, Object... args) { if (args.length > 0) bh.consume(args[0]); if (args.length > 1) bh.consume(args[1]); if (args.length > 2) bh.consume(args[2]); if (args.length > 3) bh.consume(args[3]); } public static void inlineStaticVA(Blackhole bh, Object... args) { if (args.length > 0) bh.consume(args[0]); if (args.length > 1) bh.consume(args[1]); if (args.length > 2) bh.consume(args[2]); if (args.length > 3) bh.consume(args[3]); } public void loopNonStaticVA(Blackhole bh, Object... args) { for (Object arg : args) { bh.consume(arg); } } public static void loopStaticVA(Blackhole bh, Object... args) { for (Object arg : args) { bh.consume(arg); } } }
-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining shows that all 4 options are successfully included in the caller:
@ 28 bench.VarArgs::inlineNonStaticVA (52 bytes) inline (hot) @ 27 bench.VarArgs::inlineStaticVA (52 bytes) inline (hot) @ 28 bench.VarArgs::loopNonStaticVA (35 bytes) inline (hot) @ 27 bench.VarArgs::loopStaticVA (33 bytes) inline (hot)
The results confirm that there is no difference in performance between invoking static and non-static methods.
Benchmark Mode Cnt Score Error Units VarArgs.inlineNonStatic avgt 20 9,606 ± 0,076 ns/op VarArgs.inlineStatic avgt 20 9,604 ± 0,040 ns/op VarArgs.loopNonStatic avgt 20 14,188 ± 0,154 ns/op VarArgs.loopStatic avgt 20 14,147 ± 0,059 ns/op
However, the GC profiler indicates that the vararg Object[] array is allocated for loop* methods, but not for inline* methods.
Benchmark Mode Cnt Score Error Units VarArgs.inlineNonStatic:·gc.alloc.rate.norm avgt 20 16,000 ± 0,001 B/op VarArgs.inlineStatic:·gc.alloc.rate.norm avgt 20 16,000 ± 0,001 B/op VarArgs.loopNonStatic:·gc.alloc.rate.norm avgt 20 48,000 ± 0,001 B/op VarArgs.loopStatic:·gc.alloc.rate.norm avgt 20 48,000 ± 0,001 B/op
I believe the starting point was that static methods are always monomorphic. However, the JVM can also embed polymorphic methods if there are not many real receivers on a particular call site.