Updated the benchmarks code above,
benchmarkNoInline byte code:
GETSTATIC inline/benchmark/InlineVsNoInlineBenchmark$benchmarkNoInline$1.INSTANCE : Linline/benchmark/InlineVsNoInlineBenchmark$benchmarkNoInline$1;
GETFIELD inline/benchmark/InlineVsNoInlineBenchmark.counter : I
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
INVOKESTATIC inline/benchmark/InlineVsNoInlineBenchmarkKt.invokeNoInline (Lkotlin/jvm/functions/Function2;Ljava/lang/Object;)Ljava/lang/Object;
INVOKEVIRTUAL java/lang/Number.intValue ()I
PUTFIELD inline/benchmark/InlineVsNoInlineBenchmark.counter : I
As you can see there is no “unnecessary object creation with lambda functions”, a single static function instance is used, but there is a boxing/unboxing of ints. There are the data structures you talking about?
My real-life example is a generic parsing function which receive three inline functions as parameters and orchestrates them, the first one produces the elements, the second one tokenizes them, the third one receives tokens and produces the parsing result.
Of course, I want to use inlining to gain the maximum performance. While these three functions are small everything is fine, but when they grow bigger and start to use other inline functions the generated byte code size grows bigger and bigger, at some point that will harm the performance instead of improving it, since all the generated byte code is completely exclusive to this single invocation.
I might switch to no-inline implementation, but I will loss performance because of boxing/unboxing of primitives which are passed/returned from functions. To avoid this I have to manually optimize-specialize all the four functions to factor out the generic parameters which may accept primitive types. That’s is a perfect job for the compiler, but not for a human being.