[[!meta title="Juicemacs: Exploring Speculative JIT Compilation for ELisp in Java"]] [[!meta copyright="Copyright © 2025 Kana"]] [[!inline pages="internal(2025/info/juicemacs-nav)" raw="yes"]] # Juicemacs: Exploring Speculative JIT Compilation for ELisp in Java Kana (they/them) - IRC: kanakana, Blog: https://kyo.iroiro.party - ActivityPub: @kana@f.iroiro.party - Bluesky: @kana.iroiro.party, [[!inline pages="internal(2025/info/juicemacs-before)" raw="yes"]] Just-in-time (JIT) compilation helps dynamic languages run fast, and speculative compilation makes them run faster, as has been showcased by JVMs, LuaJIT, JavaScript engines, and many more JIT runtimes. However, Emacs native-compilation, despite its JIT compilation (`native-comp-jit-compilation`), does not speculate about runtime execution, making it effectively a JIT-ish AOT (ahead-of-time) compiler. By introducing a speculative runtime for ELisp, we could potentially improve ELisp performance even further, with many new optimization opportunities. Juicemacs is my work-in-progress toy project re-implementing Emacs in Java. At its centre sits an ELisp JIT runtime powered by Graal Truffle, a JIT interpreter framework based on partial evaluation and Futamura projections. This talk will cover the following along with some demonstrations: - What is Juicemacs and its ambition? How compatible is it (or does it plan to be) with GNU Emacs and how feature-complete is it now? - What is speculative compilation? How is it useful for an ELisp JIT runtime? - How is the performance of Juicemacs compared to Emacs nativecomp? How do we interpret the benchmarks? - What is Truffle and partial evaluation? What is needed if we are to implement a speculative runtime in C without Truffle? - What JIT techniques and other things does Juicemacs plan to explore? How to get involved? Relevant links: - Accompanying blog post (slides + transcript + more discussions): (scheduled to become available after the talk) - Project repository: or - ERT testing results: - Zulip chat (devlog + discussions): About the speaker: Hello! This is Kana, an Emacs hobbyist and Java lover from China. A few years ago I discovered the Truffle JIT compilation framework and have since hoped to implement a JIT runtime myself. Last year I finally started implementing one for ELisp, called Juicemacs, and have made some progress. In this talk I will share what I've learned during the journey, including how three interpreters out of four (or more?) in Emacs are implemented in Juicemacs and how speculative compilation can make some optimizations possible. ## Discussion / notes - Q: Sorry for the explain-for-CL-user question - is what juicemacs is doing analogous to issuing a new declamation then doing something like (funcall (eval (function-lambda-expression #'my-sbcl-function))) ? - - (Thanks I had been confused about JIT a little bit) - A: I actually know very little about CL (the benchmarks come from an article linked in elisp-benchmarks). Personally I think the difference between Juicemacs and CL impl like SBCL, is that, most CL runtimes I know actually ahead-of-time compiles code, even in REPL, but Juicemacs is a JIT runtime and tries to gather statistics before compiling things (mostly through Truffle). For function calls, Juicemacs has several optimizations, like assuming unchanged function definitions (and recompile when it changes), and cache functions produced by `#'(lambda () ...)` constructs. - Q: What's the inspiration behind the name Juicemacs? - A: Since it is in Java, so I want the name to begin with 'J'. Since juice is humorously not solid, I chose that name :) - Q: Do you think the GC of Juicemacs will have similarities with the GC iterations of GNU Emacs (such as IGC)? - A: I am very much looking forward to IGC but haven't tried it yet. The difference between IGC (using MPS under the hood) and JVM GCs is that the MPS used by Emacs is conservative (GC term) and not "precise" (also GC term), in that it guesses what machine words on the stack are actual objects, but otherwise it should be a very competent GC. - Q: Just reading the blog - your experiments with Emacs are so extensive :D how'd you get started? Have you experience writing text editors? - A: Thanks! Currently, Juicemacs is mostly about an ELisp runtime though and has very little actual "text editor" things. (It has proper elisp buffers, but not display in any way - no GUI/TUI). And with a functional elisp runtime, an actual editor can (1) be fairly easy if you ignore a bunch of things mentioned in the blog, (2) or very very hard if you want to replicate Emacs. And, sadly, no, I don't have experience previously writing text editors, so my current plan is to delegate rendering to GTK (and Pango for low-level rendering to support overlays) (and other programmers by using a proper IPC protocol :-) ), and delegate editing to ELisp (which is also what Emacs does). - For getting started, I don't know? I've already started experimenting with a bit more things. Basically it is all about replicating and learning from other implementations, like Emacs and GtkTextView (and GraalJs for JIT compilers) (oh! and VS Code, I just borrowed their intervalTree.ts for overlays): it's all there, written by competent people. And all you need is maybe read them all? ;P (Experimenting with Emacs and learning about it (and crashing it sometimes) is very fun, by the way.) - Here is a little devlog: [https://juice.zulipchat.com/#narrow/channel/535506-gui/topic/Tiny.20progress.3A.20GUI.20dev.20log/with/562157361](https://juice.zulipchat.com/#narrow/channel/535506-gui/topic/Tiny.20progress.3A.20GUI.20dev.20log/with/562157361) , in which I am trying to get a GUI (and after that maybe an editor) working. - (original question-asker) -> So: read read read, smash smash smash. Love it :D and zulip is a nice idea for organising public engagement with a project, looks v cool. Thanks for sharing! - Q: GraalVM is able to run C code via LLVM; I wonder whether it would be feasible to use some of the existing Emacs code in that way - A: (Came across this interesting question on #emacs IRC.) Actually, Java has added FFI (or "Foreign Function and Memory, FFM) API very recently, so we can directly run (dynamically linked) C code without needing LLVM or GraalVM in Java. However, the thing I'm afraid of is that, Emacs is very complicated, and it seems rather impossible to just use "some" of its existing code without incorporating a whole GNU Emacs... (For example, even passing a cons list from Java to C code is very hard, since we need to now care about ABI compatibility. Not to mention that in many places Emacs just assumes it is run with its built-in GC.) But, speaking of FFM, I think we can make very good use of it to support Emacs dynamic modules (right now I'm also listening to the Emacs PDF reader talk, which is also a dynamic module). As far as I know, the API interface of Emacs dynamic modules is very clearly decoupled from Emacs internals (when reading /usr/include/emacs-module.h, which seems to make its `struct emacs_value` opaque, meaning that we can use any pointer, or even Java object references in that pointer), and we should be able to support any dynamic modules out there with FFM. - [https://codeberg.org/gudzpoz/Juicemacs](https://codeberg.org/gudzpoz/Juicemacs) - The blog article is now online: [https://kyo.iroiro.party/en/posts/juicemacs-exploring-jit-for-elisp/](https://kyo.iroiro.party/en/posts/juicemacs-exploring-jit-for-elisp/) - Wonderful explanations!  Thank you for taking the time to share your wisdom. - A very impressive project! Thanks for presenting it - [https://juice.zulipchat.com](https://juice.zulipchat.com) - Very exciting project! - yet another exciting emacs clone lets goo!! - I really want to end up with a formal specification of emacs lisp one day - juicemacs elisp is suprisingly far along - your jit compiled elisp is impressive - Thanks, I know a little more about JIT now ! - Kana here! Thanks! Please feel free to ask any question. I'm also trying out a Zulip chat server for maybe lengthier discussions: https://juice.zulipchat.com . [[!inline pages="internal(2025/info/juicemacs-after)" raw="yes"]] [[!inline pages="internal(2025/info/juicemacs-nav)" raw="yes"]]