Is it possible to run a Kotlin compiler plugin ove...
# compiler
j
Is it possible to run a Kotlin compiler plugin over all of the Kotlin IR which will be emitted as JS (both within the module plus all dependencies) and mutate that IR? I have a custom plugin which I added to the JS link task which is successfully having its
registerExtensions
function called, but a registering an
IrGenerationExtension
normally doesn't seem to have it be called. Is there something else I can do to make this work?
I asked this like 1.5yrs ago, but I never got around to trying it. Trying now... https://kotlinlang.slack.com/archives/C7L3JB43G/p1698116255957259
t
Let me know if you find something like this. Are you working on component registry building?
p
If talking about component registry building, i've managed to solve it by creating global registry object and eager initialization of components registering them in that registry that happens before main function. Firstly to make eager initialization works in gradle.properties need to add line:
Copy code
kotlin.js.ir.output.granularity=whole-program
And some minimal code example: // at core library object Registry {     fun register(component: Any) {         ...     } } // at component file @Component class TestComponent // below is IR generated code for Js/WasmJs (in the same file with TestComponent) @EagerInitialization val TestComponentInit_: Unit = run {     Registry.register(TestComponent()) }
In this solution IR generated with compilation of each needed class. No need to keep whole program classes for IR generation.
t
Good tip, thank you, I'll look into the details. How does this affect incremental compilation?
p
I have no issues with IC. Every time class recompiles IR also regenerated.
t
I mean, is this setting in conflict with IC? At least it has to load the "whole program" to generate output.
p
I can't find answer in docs. Seems like there is no relation between output format and IR incremental compilation. Reading here: https://kotlinlang.org/docs/js-ir-compiler.html#incremental-compilation-for-development-binaries
j
I am not doing component registry
I want to delete function calls across my entire Kotlin transitive dependency graph before they get emitted as JS
d
It's not possible, compiler plugins are not called at the second compilation stage (one which generates JS/Wasm/LLVM from all klibs) cc @Wojciech Litewka
👍 1
w
Yes, the compilation of non-JVM backends is divided into two states: on the first one, each kotlin module is compiled into a separate Klib. Somewhere inside,
IrGenerationExtension
is invoked, with
IrModuleFragment
representing that module. On the second stage, this and all dependent klibs are read at once and transformed into JS file(s). This is the whole-world IR you are asking about, but unfortunately plugins are not invoked there. It is theoretically possible to add a new extension point for the second stage that would receive the whole IR (
List<IrModuleFragment>
, as the compiler sees it), but it would likely be even more unstable than the current plugin API given our active development in this area.
j
Thanks for the information. For what it's worth, this is for our own internal usage where we are far more tolerant to instability than something that we ship as a library to a bunch of users. We are looking to perform some simple whole-program optimizations to release builds, similar to what R8 does for Android/JVM. Is this a use case that you would consider as valid? Doing it in Kotlin's IR seems much easier than the alternatives if it were supported.
w
That's a valid use case, sure. But quite specific as well - there is no such option for JVM, and specifics on other backends may also vary, especially when it comes to incremental compilation. So we most likely won't provide it as an extension point. If you'd still like to try how would it work on a hacked compiler, I suggest you insert your transformations somewhere around here (note that's only for JS and without IC).
j
For JVM there are well-established libraries for manipulation of its bytecode and Kotlin fits naturally into that ecosystem so its produced bytecode is also relatively easy to manipulate (especially if you aren't touching ABI/metadata). JS and native are harder to manipulate. JS is harder only because Kotlin has to emulate lots of concepts which don't exist in the language. Native is hard, well, because it's native. Wasm isn't too bad, much closer to Java bytecode and its tools are progressing. Since this would be for release builds only, not at all worried about IC
1
v
Thanks for your input! The requested feature has been just discussed, and it’s doable as medium-size task, with necessary changes in test infra, which are still TBD. Meanwhile your votes and comments are welcomed to better estimate its severity and priority.
j
Oh, nice. Thanks!