Live data from Hacker News

Jank now has its own custom IR

jank-lang.org

11–20 of 57 posts

Re: Jank now has its own custom IR

#12
The natural evolution of compiler toolchains that live long enough on top of LLVM, eventually every one matures into having their own IR.

Even clang is now in the process of doing the same.

> We're going to use Clojure JVM to get our baseline benchmark numbers and then we'll aim to beat those numbers with jank.

> Note that all numbers in this post are measured on my five year old x86_64 desktop with an AMD Ryzen Threadripper 2950X on NixOS with OpenJDK 21. When I say "JVM" in this post, I mean OpenJDK 21.

In 2026, a better baseline would be the Java 26 implementations of OpenJDK, OpenJ9, and GraalVM, with JIT cache across several execution runs.

> In the native world, we don't currently have JIT optimization. It could exist, but LLVM doesn't have any implementation for it and neither does any major C or C++ compiler

Yes they kind of have, that is partially what PGO is used for, to get the program behaviour during training runs, and feed it back into the compilation toolchain.

Also while it isn't native code per se, when targeting bytecode environments like IBM i, WebAssembly, CLR, among others, with C or C++, there is certainly the possibility of having a JIT in the picture.

> Finally, just because jank is written in C++ doesn't mean that we can escape Clojure's semantics. Clojure is dynamically typed, garbage collected, and polymorphic as all get out.

Which is why, benchmarks should also take into account compilers for Common Lisp and Scheme compilers.

Anyway, great piece of work, and it was a very interesting post to read, best wishes to the author finding some support.

Re: Jank now has its own custom IR

#13
post #10

> we're using it to optimize jank to compete with the JVM The JVM gets a lot of hate, but that is a very high bar. The JVM is a serious piece of kit. I hope Jank succeeds. I'd love to use it in real projects.

Additionally, there are many JVMs to chose from, many always make the mistake to equate JVM with OpenJDK, which is like talking about C and only considering GCC or something. Other JVMs have plenty of goodies, some of them have AOT for about 20 years now, others real time GC, other ones JIT caches before Project Leyden was even an idea, others actual value types as experiment (ObjectLayout on Azul), pauseless GC, clo…

On the other hand, the JVM spec may prohibit some optimizations you are after. It's very dynamic after all!

Re: Jank now has its own custom IR

#14
post #13
post #10

Earlier quoted context omitted.

Additionally, there are many JVMs to chose from, many always make the mistake to equate JVM with OpenJDK, which is like talking about C and only considering GCC or something. Other JVMs have plenty of goodies, some of them have AOT for about 20 years now, others real time GC, other ones JIT caches before Project Leyden was even an idea, others actual value types as experiment (ObjectLayout on Azul), pauseless GC, clo…

On the other hand, the JVM spec may prohibit some optimizations you are after. It's very dynamic after all!

Not really, that is the usual argument why CPython is slow.

If anything runtimes like the various JVM implementations, alongside the CLR and JS engines as well, are the bleeding edge of dynamic compiler optimizations with dynamic runtimes.

That is something that gets lost when talking about Java, yes the programming language looks like C++, however the JVM itself is heavily inspired by Smalltalk and Objective-C dynamic semantics.

Coming back to the spec, you will notice that it doesn't mention how threads are implemented, what kind of AOT/JIT are available, or what GC algorithms to implement, leaving enough room space for implementations.

One area where you are actually right, that I just remembered while typing this, are the way reflection or unsafe code hinders some optimizations, hence the ongoing steps that enabling JNI or FFM has to be explicit at startup, dynamic agents also have to be expliclity enabled, and the upcoming final means final (no more changing final fields via reflection).

Re: Jank now has its own custom IR

#15
post #14
post #13

Earlier quoted context omitted.

On the other hand, the JVM spec may prohibit some optimizations you are after. It's very dynamic after all!

Not really, that is the usual argument why CPython is slow. If anything runtimes like the various JVM implementations, alongside the CLR and JS engines as well, are the bleeding edge of dynamic compiler optimizations with dynamic runtimes. That is something that gets lost when talking about Java, yes the programming language looks like C++, however the JVM itself is heavily inspired by Smalltalk and Objective-C dynam…

what really matters is :

how far can i get in X programming language by writing just idiomatic code?

how much of SDK and community libs, frameworks help me run my program at bare metal speed ?

What sort of change i have to do exisitng libs, frameworks and my legacy code for CPU, IO and memory efficiency as a migrate to new version ?

Re: Jank now has its own custom IR

#16
post #14

Earlier quoted context omitted.

Not really, that is the usual argument why CPython is slow. If anything runtimes like the various JVM implementations, alongside the CLR and JS engines as well, are the bleeding edge of dynamic compiler optimizations with dynamic runtimes. That is something that gets lost when talking about Java, yes the programming language looks like C++, however the JVM itself is heavily inspired by Smalltalk and Objective-C dynam…

what really matters is : how far can i get in X programming language by writing just idiomatic code? how much of SDK and community libs, frameworks help me run my program at bare metal speed ? What sort of change i have to do exisitng libs, frameworks and my legacy code for CPU, IO and memory efficiency as a migrate to new version ?

That is only part of the picture, the other part that seems quite forgotten nowadays is:

- how much people actually care about algorithms and data structures

- do they actually know what options their tools have available

- have they ever spend at least an hour reading the man pages, info page or HTML documentations

- have they ever used a profiler, a graphical debugger, an advanced IDE

Re: Jank now has its own custom IR

#17
post #4

Great article, as always. There is one thing that I think is important to bear in mind when discussing inlining, especially in the context of Clojure. This is that once a function has been inlined, you can no longer update the definition of that function in the REPL and have that update the behaviour of functions which use it, unless you recompile those as well. This is not a criticism of course, it’s just part of th…

Julia actually has some really cool machinery for handling this that I would encourage other JIT languages to copy.

Whenever you call a function, that function and any calls in that call stack occur in a 'fixed world age'. Within a given world-age, method tables and global constants are all fixed, and the langauge can be analyzed like it's statically typed (there are escape hatches like `invoke_in_world`, and `invokelatest`)

Between world-ages, things are allowed to change. When a function calls another function, we add a 'backedge' from the caller to the callee.

So if I have `f(x) = g(h(x))`, and I redefine `h`, we then say it's no longer valid, and then we look at the backedge that leads from `h` to `g` and say the old definition of `g` is also no longer valid, and then we go from `g` to `f` and also invalidate the old definition of `f`.

This means that once `f` is called in a new world age (the world-age gets incremented every time a new method is (re)defined, or if a global const is changed / defined), the compiler knows that it has to recompile `f`, `g`, and `h`. What's especially cool is that this system works regardless of inlining, and it allows us to safely do all sorts of interproceedural optimizations, but in a JIT compiled language.

Re: Jank now has its own custom IR

#18
post #12

The natural evolution of compiler toolchains that live long enough on top of LLVM, eventually every one matures into having their own IR. Even clang is now in the process of doing the same. > We're going to use Clojure JVM to get our baseline benchmark numbers and then we'll aim to beat those numbers with jank. > Note that all numbers in this post are measured on my five year old x86_64 desktop with an AMD Ryzen Thre…

Isn't the main benefit of LLVM that you get tons of backends for free? What does having your own IR give you that's worth this tradeoff?

Re: Jank now has its own custom IR

#19
post #9
post #6

Earlier quoted context omitted.

Does that not happen automatically? I know there are contexts in which jvm will deoptimize inlining and recompile, like in response to class loading that causes a call site that was previously provably monomorphic to no longer be.

No, it doesn't. In JVM Clojure's case, the vars are usually compiled to the moral equivalent of a global variable holding a pointer to a function. This allows you to update the function if the developer redefines it in the REPL, but it comes at a performance cost (the JVM can't inline it or otherwise optimise it). Clojure also allows you to compile with "direct linking", e.g. for production deployments, where you kno…

> the vars are usually compiled to the moral equivalent of a global variable holding a pointer to a function. This allows you to update the function if the developer redefines it in the REPL, but it comes at a performance cost (the JVM can't inline it or otherwise optimise it)

might be out of my depth but I find it surprising; I thought compilation through invokedynamic should be able to handle redefinition while still allowing inlining and other jit optimizations

Re: Jank now has its own custom IR

#20
post #18
post #12

The natural evolution of compiler toolchains that live long enough on top of LLVM, eventually every one matures into having their own IR. Even clang is now in the process of doing the same. > We're going to use Clojure JVM to get our baseline benchmark numbers and then we'll aim to beat those numbers with jank. > Note that all numbers in this post are measured on my five year old x86_64 desktop with an AMD Ryzen Thre…

Isn't the main benefit of LLVM that you get tons of backends for free? What does having your own IR give you that's worth this tradeoff?

These compilers aren't replacing LLVM, they are adding a compilation step with its own IR where they do certain optimizations and translations *before* handing things off to LLVM.

Basically, the idea is to do as much 'high level' optimization and transformation stuff as you can in your own IR, and then let LLVM handle the low-level stuff and the targeting of specific hardware vendors.

Post reply on HN