Using the standard library with kotlin-js -Xir

I’m trying to compile a Kotlin program into an IR file serialized with protobuf. I tried using the kotlinc-js compiler for that (with <kotlin-home>/bin/kotlinc-js -Xir -Xir-produce-only=klib main.kt -output test -kotlin-home <kotlin-home> -verbose). The compiler always complains about not finding types from the standard library though:

exception: java.lang.AssertionError: Built-in class kotlin.Unit is not found
        at org.jetbrains.kotlin.builtins.KotlinBuiltIns$3.invoke(KotlinBuiltIns.java:113)
        at org.jetbrains.kotlin.builtins.KotlinBuiltIns$3.invoke(KotlinBuiltIns.java:108)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$MapBasedMemoizedFunction.invoke(LockBasedStorageManager.java:440)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$MapBasedMemoizedFunctionToNotNull.invoke(LockBasedStorageManager.java:515)
        at org.jetbrains.kotlin.builtins.KotlinBuiltIns.getBuiltInClassByName(KotlinBuiltIns.java:362)
        at org.jetbrains.kotlin.builtins.KotlinBuiltIns.getUnit(KotlinBuiltIns.java:437)
        at org.jetbrains.kotlin.builtins.KotlinBuiltIns.getUnitType(KotlinBuiltIns.java:707)

When the -Xir-related flags are omitted, it compiles to js without any problem, but I only need the intermediate representation.

Am I passing some wrong argument here? If kotlinc-js is not suitable to generate IR files, is there another tool I could use?

1 Like

Such compiler mode requires the standard library in IR format either. We do not ship this library in that format with the compiler yet, so you may need to build it manually. Or you can wait for Kotlin 1.3.60 in which we hope to provide a suitable dual-format standard library for Kotlin/JS.

Thanks for the reply - I ended up passing the source for the standard library as inputs with Xallow-kotlin-package, but I couldn’t quite get it to compile yet.

In the end, I’m trying to compile Kotlin to another target by generating Kotlin interfaces like these, compiling Kotlin using those interfaces to IR and then translate that to the target.
I probably won’t need the whole js library, I mainly looked at kotlinc-js -Xir because it promises to output IR files. I’m wondering if there are other options available to compile Kotlin source code to a (preferably lowered) intermediate representation?

You don’t need to compile the standard library with your code, you need to compile it separately and pass it as a dependency. You can do it currently by checking out kotlin repository (better at the version matching the version of the compiler, supposedly in 1.3.50 branch) and then running gradlew :kotlin-stdlib-js-ir:assemble task. The resulting artifact will be produced in the libraries/stdlib/js-ir/build/libs directory.

Thanks! I’ve managed to compile the stdlib. I’m surprised about the layout in the generated jar file though. In its “ir” folder, there’s an “ir_tables” subfolder which contains “irCombined.knd” and “symbols.knd” (among others). Judging by the IrKotlinLibraryLayout, shouldn’t all those files be directly in the “ir” folder? I can’t extract anything with kotlin-util-klib.

In the end, I just need a serialized form of IR after lowerings - is there another way to obtain that?

Hi @sbinder! I don’t think we have a tested way to serialize/deserialize lowered IR. We serialize it into klibs after psi2ir but before lowerings.

May I ask, why do you need such a thing?

May I ask, why do you need such a thing?

I’m trying to compile Kotlin to another language (Dart Kernel). I’ve seen that the IR serialization uses protobuf, so I figured the minimum-work approach for this would be to

  1. Use the Kotlin Compiler to obtain serialized Kotlin IR
  2. Load that IR in a Dart program and compile to Kernel

This let’s me use most of Kotlin’s toolchain and I can use existing Dart libraries to write Kernel.

We serialize it into klibs after psi2ir but before lowerings.

That’s understandable, I guess lowering doesn’t really make sense for libraries that are meant to be published.

You mentioned there isn’t a tested way, but I’m wondering how lowering could break serialization. I imagine lowered IR is a subset of IR? Maybe there could be a compiler flag to kotlin-js -Xir (or any other tool) that makes it emit lowered IR.

I’m trying to compile Kotlin to another language (Dart Kernel )

I’m intrigued! What kind of use-cases do you want to cover? Are you targeting Dart Web, Flutter?

Load that IR in a Dart program and compile to Kernel

Note that binary format and set of lowerings can change in the future.

This let’s me use most of Kotlin’s toolchain

At the moment lowered IR is very platform specific. In case of Kotlin/JS, IR is partialliy lowered to JavaScript dynamic operations. It would not be feasible to compile this IR back to a typed language. JVM and Native lowerings have a lot of platform assumptions too.

Also, all platforms implement core parts of runtime/stdlib differently, sharing a common subset of public interface. K/JVM maps stdlib declarations to Java classes, K/JS heavily uses JavaScript built-ins, and Native implements some functionality in C++. Some lowerings rely on these runtime details.

A mark // Common prefix ends in lowering phases list roughly indicates where lowerings are starting to become more platform-specific.

Thanks for the detailed reply!

What kind of use-cases do you want to cover? Are you targeting Dart Web, Flutter?

All Dart compilers and runtimes are based on Kernel, so hopefully all of them. Dart native & Flutter would be the most interesting of course, web might be worth a look because dart2js can apply strong global optimizations.

At the moment lowered IR is very platform specific

Okay, looks like I’ll have to write some of my own lowerings then. I’ll study the other compilers and see how I can adapt this to Dart. Thank you again for all the helpful pointers!

Hello again. I managed to write a compiler that can compile some simple Kotlin programs to Dart Kernel that runs on the Dart VM and with dart2js (repo).
So far, I used the TopDownAnalyzerFacadeForJVM to obtain the module descriptor and binding context for psi2ir. I’m just using the regular JVM stdlib and then implement calls to the stdlib as compiler intrinsics here.

Now, I’m looking for ways to call Dart methods from Kotlin and eventually implement a Dart-specific stdlib. I’m a bit overwhelmed by the analyzer and what’s actually needed to resolve code:

  1. What do I need for a minimum analyzer implementation with Dart interop? I can write something to list available Dart members and create Kotlin descriptors for packages/classses/methods etc. Do I just need a PackageFragmentProvider?
  2. As soon as I go away from the JVM analyzer, I’ll likely need another way to make the standard library and builtins available. Can I just pass my custom stdlib as sources somehow?

I’d very much appreciate some pointers in the right direction.