Different question. Are there any current plans to...
# compiler
y
Different question. Are there any current plans to eventually use JVM IR for inlining? or just any plans to include serialised JVM IR in published jars? Because that can be immensely useful for compiler plugins that need to use IR from external sources. For example, I'm currently performing inlining manually on the IR level, and so on the JVM I have to do a few hacks with finding the sources jar for a file and compiling that source to use its IR, but if I had access to serialised IR, I can just deserialise that and inline it directly.
đź‘€ 1
u
There are plans to serialize IR for inline functions to .class files and deserialize it upon inlining, which we’re discussing internally. We’re also working on a prototype which at the beginning will be used for experimental support of inline “constexpr” functions (KT-14652). The main obstacles for serializing/deserializing IR for inline functions right now are: 1) The serialization format we already have for IR (which is used for .klib in Native & JS) was designed for the “closed world” model and is unsuitable for the JVM. The main problem is that when inlining a function from another module, you might not have access to all dependencies of that module, and IR doesn’t have all the information to determine how to generate bytecode for such missing dependencies. We have an approximate idea of a solution, but it’s not well thought/tested yet. 2) The serialization format is also not ready for the compatibility guarantees we provide for Kotlin/JVM (full backward compatibility; forward compatibility for 1 major version) and needs some changes before we can commit to supporting it. Or at least we can decide that we won’t provide such compatibility guarantees specifically for IR of inlined functions on JVM, and fallback to bytecode inliner. 3) We’ll still need to support inlining from the bytecode because the compiler needs to be compatible with existing bytecode from Kotlin 1.0. And bytecode inliner is a very complicated (maybe the most complicated) part of the compiler codebase, which it seems we can’t just throw away. So if we’re replacing it with IR inliner, we’ll need to come up with strong reasons to split the implementation in such way and properly support both inliners from then on.
đź‘€ 2
y
@udalov The
constexpr
feature is actually incredibly promising because it'll add a lot of the things I possibly stumbled with directly to the compiler (namely the inlining bit but also deserialising specific portions of IR). I do wonder, though, how the serialised IR will be stored inside a
.class
file, because I figured you would go for a similar approach to JS and Native and store it inside of the
jar
itself instead (maybe as a sibling file to the
.class
file). Is there any possibility that you could distribute JVM jars that include everything as IR, including non-inline functions? or would that be too much of an overhead on library size?
constexpr
can even work for my "inlining returned lambdas" use case in some scenarios, but usually in most scenarios more complex logic is required that, quite aptly, isn't `const`ant. I wonder if that'll make that use case easier though (and solve some oddities like having an
IrBlock
around an
IrFunctionExpression
causing it not to be inlined for whatever reason). I guess only time will tell. I thought, btw, that you do technically have access to the dependencies of other modules because they are on your module's classpath because like for example if a library uses another library as
implementation
in Gradle, that other library is still on your classpath (I think), but maybe its only exposed if its
api
. A strong reason for supporting it is clearly `constexpr`s, but also, IIRC, some optimisations are IR specific and aren't applied to JVM bytecode, and so by inlining IR you could possibly get more optimisations for free.
u
I do wonder, though, how the serialised IR will be stored inside a .class file
In the current prototype, it’s serialized via protobuf, converted to modified UTF-8 and stored inside an annotation on the class file.
Is there any possibility that you could distribute JVM jars that include everything as IR, including non-inline functions? or would that be too much of an overhead on library size?
Currently we don’t have plans for this, mostly because we don’t have enough use cases in the compiler itself, and indeed the overhead would be large. Those use cases may appear in the future though, mostly in the multiplatform support.
I thought, btw, that you do technically have access to the dependencies of other modules because they are on your module’s classpath because like for example if a library uses another library as implementation in Gradle, that other library is still on your classpath (I think), but maybe its only exposed if its api.
The implementation dependency is used precisely if you need to use something, for example, in a function body (not in the signature), yet your clients may know nothing about it. Such dependency is not carried transitively to your clients. The problem is that with current Kotlin and bytecode inliner, you can have a public inline function which references something from an implementation dependency, and it will get inlined correctly at call sites in other modules. With IR this won’t work out of the box, because the IR still needs to be lowered at a call site, and for that we need to know a lot about the declarations referenced in the inline function body (whether they are declared in Kotlin or Java, which annotations they have, etc).
A strong reason for supporting it is clearly constexprs, but also, IIRC, some optimisations are IR specific and aren’t applied to JVM bytecode, and so by inlining IR you could possibly get more optimisations for free.
Yeah, those are our main candidates so far as well. We managed to achieve a lot already with the bytecode inliner and post-processing transformations, but some things, like potential ideas of loop fusion optimizations or some advanced elimination of unnecessary boxing/unboxing, are just extremely cumbersome to do on the bytecode.