1. 26
    1. 5

      This is super cool work.

      Every time I hear about somebody putting clojure on a new platform, I think, would I use this? In cases where the relevant platform is very hard to package in its own right, my answer has been no. But for this, I think the ability to actually compile down to an actual binary? That’s super cool.

      Which leads to perhaps the most unfortunate question I could ask: Is it expected that jank will support nrepl?

      1. 5

        Yes. :) REPL-based workflows are first and foremost in jank, just as in Clojure. AOT compilation is the easy bit, since that’s how native works normally, so I’ve started with the JIT workflow to ensure everything is solid there first. jank does this in two forms, as of this latest post:

        1. It JIT compiles C++ code (using Clang/LLVM tooling to do so), which allows (specially crafted) C++ files to be required as normal jank namespaces
        2. It JIT compiles LLVM IR generated by the jank compiler

        But, put simply, once jank is released, you should just be able to connect your REPL client to it and get going. There really isn’t much art in this space right now, marrying the native world with the interactive programming world. I’m looking forward to presenting in front of C++ gamedevs, in the future, and showing how we can build native games with a REPL client. :D

        1. 1

          So, pardon my ignorance because I am not a language designer by any stretch of imagination. Wouldn’t having a REPL attached to a Jank program require LLVM either on the target or the host? Ideally the host, by which I mean where the REPL is being started, not the target that runs the program.

          1. 5

            Yes. LLVM is linked into jank, just as it’s linked into Clang. This allows it to JIT compile code at runtime. Any program built with jank will then have all of jank (and LLVM) linked into it as well.

            There will, in the future, be an option for static AOT builds, which don’t have any JIT compilation capabilities. So LLVM can be elided, LTO can be performed, etc. But, generally speaking, the jank compiler/runtime contains LLVM and jank programs contain the jank compiler/runtime.

      2. 4

        This is very interesting to me because over in TLA+ land we use a tree-walk interpreter that runs in the JVM for our finite model checker. Calvin Loncaric did a quick prototype of transpiling a very limited subset of TLA+ to C instead, just to see what kind of performance we would get - IIRC it beat the existing model-checker by a factor of 10,000! So creating some next-gen finite model checker that emits native bytecode has been bouncing around the back of my head.

        I’m trying to figure out from the post - do you transpile your dialect to C and then use LLVM to get the IR? Or do you emit the IR directly? Also, how portable is this? How large of a binary do you need to ship with jank to get LLVM IR JIT compilation?

        1. 3

          The main branch of jank is generating C++ right now, then using Clang to JIT compile that in memory to machine code. However, this post covers my work in migrating to generating LLVM IR directly in memory, to give to LLVM to JIT compile. I haven’t finished this migration yet, but I will in the next month.

          jank’s runtime performance is good; it can compete strongly with Clojure JVM, even though jank has no hotspot JIT optimizer. Its base level performance is on part with JIT optimized Clojure. Keep in mind that, although jank is native, it still has a super polymorphic runtime, due to the nature of Clojure. So it can’t compare to hand-written C++ which use structs and references, since basically everything in jank needs to be boxed and all data is in persistent, immutable data structures.

          jank is portable in so far as it can work on Linux, macOS, and Windows. However, since jank is a 100% Clojure dialect, that means it’s garbage collected and uses exceptions, so running jank in a super constrained environment may be tough.

          Linking in LLVM causes jank’s binary to be quite large. This can be drastically cut down during AOT compilation and I haven’t spent any time optimizing it yet. Currently sits at 200MB, due to static linking. We should expect jank’s compiler to be about the size of Rust’s compiler, since they’re doing similar work.

          With jank, you will have two AOT compilation options: static runtime or dynamic runtime. With the dynamic runtime, you have an AOT build, but you still can JIT compile anything, you still have Clang/LLVM linked in, and the entire program can be redefined dynamically. With the static runtime, all of that gets stripped out. There will be no JIT compilation abilities, functions can be directly linked and thus inlined, and whole-program LTO can run. This is the ideal for production releases.

          1. 1

            That’s very interesting. So you just transform the parse tree into a giant string that you build up in memory, then pass that into some API exposed by the LLVM libraries, no having to mess around with the filesystem? Very nice.

            200MB

            Ack! That’s the size of an entire minified Debian image! Ah well, storage is cheap but time is not.

            1. 3

              In lisps, the parse tree is just the code itself, as data. Then the AST ends up being more robust. We translate the AST to LLVM IR, but it’s much better than string building, since LLVM makes it pretty darn easy using their IRBuilder. Check it out: https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.html

          2. 2

            I’d be interested in looking into this but don’t know much about TLA+ – just generally making runtimes faster. Would like to chat.

            Re: jank: probably using LLVM as library to emit IR in memory; going through C/C++ is slow.

            1. 1

              Sent you an email at the address I found on your website!

          3. 2

            Congrats on transitioning to full time! Hope you get funded soon!

            1. 1

              Picolisp written on raw llvm-ir. Works.