de en en pt es en en en en cv az en de en en en en en en en en en en en ca es en es ne en en en en en en en en en en en fr en en hu en en fr en en en en en en en fr en en en fr en en ru en en fr en en en it fr en en en en en en en it en en en en en en en en en en en en en en en en en en en en en en en en en en en zh nl en en en en en en en en en en en en en en it en en en en en en en pt en en en en en en en en en
One of the main goals of ZetaVM is to be very approachable, and enable more people to create their own programming languages, or to experiment with language design. With that goal in mind, I’ve designed a textual, stack-based bytecode format that resembles JSON, but allows for cycles (objects can reference one-another). Functions, basic blocks, and instructions in this bytecode format are all described as a graph of JS-like objects. This is very user-friendly. Anyone can write a Python script that outputs code in this format and run the output in ZetaVM. It’s also very powerful, in a LISP-y code-is-data kind of way: you can generate and introspect bytecode at run time, it’s just made of plain objects and values that the VM can manipulate. ZetaVM has first-class bytecode.
The downside of all this, as you can imagine, is that it inherently has to be absolutely dog slow. Or does it? The first version of the Zeta interpreter traversed the graph of bytecode objects the naive way, and it was indeed dog slow. I’ve since written a new interpreter which removes the overhead of the object-based bytecode by dynamically translating it to an internal representation (think dynamic binary translation). The internal IR is compact and flat, executing it involves no pointer hopping.
The new interpreter generates code on the fly, which means it is, by definition, a Just-In-Time (JIT) compiler. It’s architecture is based on Basic Block Versioning (BBV), a compilation technique I developed during my PhD (talks and papers on the topic are linked here if you’re curious). BBV has the nice property that it generates code lazily, and the generated code naturally ends up compact and fairly linear. This is not done yet, but BBV also makes it possible to specialize code to eliminate dynamic type checks very effectively, and to perform various optimizations on the fly.
You might be wondering why I’m bothering with an interpreter, instead of just writing a JIT that generates machine code. One of the motivating factors is that Zeta is still at a very early stage, and I think that an interpreter is a better choice for prototyping things. Another factor is that it occurred to me that I could potentially make Zeta more portable by having the interpreter do much of the compilation and optimization work. The interpreter can do type-specialization, inlining and various code simplifications.
The interpreter will be designed in such a way that the internal IR it produces is optimized and in many ways very close to machine code. It should then be possible to add a thin JIT layer on top to generate actual machine code. The resulting JIT will hopefully be much simpler and easier to maintain than if one were compiling directly from the raw object-based bytecode format. Another benefit of this design is that all of the optimizations that the interpreter perform will not be tied in with the specifics of x86 or other architectures, they will remain portable.
At the moment, the new interpreter is at a point where it lazily compiles code into the flat internal format, but performs no other optimization. This was enough to get a 7x performance improvement over the naive interpreter, but the current system is still quite a bit below the performance level of the Python interpreter, and there is definite room for improvement. Some of the first optimizations I would like to introduce are the elimination of redundant branching instructions, and the use of inline caching to speed up function calls.
The elimination of redundant branches is fairly easy to do with BBV. Code is lazily compiled, and appended linearly into a buffer. When generating code for a branch, if the block we are jumping to is just about to be compiled, then the branch is redundant. BBV will naturally tend to generate code that flows linearly along hot code paths and branches out-of-line for infrequent code paths. That is, the default path often comes right next and requires no branching.
Inline caching is a classic technique that was pioneered by the Smalltalk and SELF VMs. It’s used, among other things, to eliminate dynamic property lookups when polymorphic function calls are performed (see this excellent blog post for more information). Currently, ZetaVM, when performing a function call, needs to read multiple properties on function objects. For instance, it needs to find out how many arguments the function has, and what is its entry basic block. These property lookups are dynamic, and relatively slow. The end result is that the call instruction is very slow compared to other instructions.
Most call instructions will end up always calling the same instruction. Hence, dynamic overhead on function calls can largely be eliminated by caching the identity of the function being called by a given call instruction. That is, one can cache the number of arguments and entry basic block associated with a function object the first time a call instruction is run, and then reuse this information when calling the function again, provided we keep calling the same function. This information will be cached in line, in the instruction stream, right after the call instruction opcode, hence the name inline caching. I anticipate that with inline caching, function calls in Zeta can be made several times faster.
just have fun with it
and forget everything else
this is super awesome.
Exciting to see where this goes, this project has sparked my interest in making my own language.
Thank you. Glad to hear your interest was sparked. What kind of language are you interested in creating? :)
Very excited to read more about this! I’m working on a dynamic language that has gradual-typing, would that be possible with ZetaVM?
Absolutely. As a matter of fact, a friend has gotten a paper accepted into a major conference, which uses the JIT compiler I developed for my PhD to implement gradual typing. He has gotten very good results. Zeta will use the same kind of JIT, and will also have powerful dynamic type check elimination, so it should work quite well for gradual typing :)
Hi Maxime. Fantastic project! I don’t know too much about compilers/VMs/CompSci but was curious what your thoughts are on the Ethereum VM (EVM). The EVM has only one stable high level language (Solidity) and we as app/Dapp developers have experienced issues with this language and I would like a way to experiment with language creation for the EVM. Forgive the ignorance of this question, but would it possible to have ZetaVM as an intermediate VM target for ultimately targeting the EVM as runtime? It would require some kind of ZetaVM=>EVM transpiler/translator or shim right?
I’d like to see a high level EVM language that is strongly typed (maybe Typescript or Python inspired due to popularity) and amenable to formal verification. I know we should probably just bite the bullet and target the EVM directly, but there seem to be so many cool features in the ZetaVM that I’d like to explore that for HLL exploration and see if some of the features can be implemented on the EVM using a ZetaVM to EVM transpiler or translator.
BTW I moved from Montreal to Silicon Valley in 1999. It was a bit of a culture shock. Growing up in the boring ‘burbs (Beaconsfield) made it easier, but I agree there’s nothing here that even approximates downtown Montreal at night. :) Thanks for being so available to answer questions, and please ignore any negativity on hackernews or reddit, it’s a wonderful project!
It might be possible to compile from Zeta bytecode to EVM bytecode. I would have to look into the specifics, but since Zeta bytecode is first-class, it might be possible to write a Zeta library that does this. Strongly typed languages are definitely feasible. Would you be interested in working on this sort of thing?
I moved to Silicon Valley and worked at Apple for a year. Now back in Montreal. The pay was great, the work environment was good too, but I ultimately felt too isolated living in the suburbs, and missed my friends and family here.
I’d certainly be interested in working on it. It would be a real learning experience for me as I’m barely a front-end web developer. I’m looking forward to giving it a try. I guess I’ll start by trying to understand both VMs. Thanks! -Andy
I just took a brief look at the EVM bytecode, and compiling Zeta bytecode to it looks definitely feasible. Would be really cool to have a library that does this.
By the way, I just created a gitter chat for ZetaVM. Feel free to join: https://gitter.im/zeta-vm-org/Lobby :)
When you have time take a look at unison project, a new programming platform.
Did you study Erlang VM named BEAM?
There is an interesting paper “BEAMJIT – A Just-in-Time Compiling Runtime for Erlang” where authors did describe their approach based on reusing parts from VM code on building the JIT.
Was interested in the Lisp comment :) Combinations of the right things can give very good results.
2 seconds full build from source.
Be interested in any comments if you happen to take a look.
Good luck with the new project.
Leave a Reply Cancel reply
Enter your comment here...
Fill in your details below or click an icon to log in:
Email (required) (Address never made public)
You are commenting using your WordPress.com account. ( Log Out /  Change )
You are commenting using your Twitter account. ( Log Out /  Change )
You are commenting using your Facebook account. ( Log Out /  Change )
Notify me of new comments via email.
Notify me of new posts via email.
« The AI Risk Isn’t What You Think
ZetaVM, my new compiler project »
Typed vs Untyped Virtual Machines
Minimalism in Programming Language Design
Democracy, Dictatorships and Access to Information
Code that Doesn’t Rot
The Internet Changed My Life
What’s Could You Use Tesla Bot For?
NoiseCraft: a Browser-Based Visual Programming Language for Sound & Music
Art Artificial Intelligence Artificial Life Assembly Biology Compilers Creativity D Language Electronics Future Game Development Genetic Algorithms Grad studies Graphics Higgs JavaScript Microcontrollers Microprocessors Music Programming Programming Languages Psychology Rant Robotics Tachyon Technology Uncategorized work x86 Zeta
Archives Select Month June 2022  (1) May 2022  (1) March 2022  (1) February 2022  (2) January 2022  (2) December 2021  (1) June 2021  (1) February 2021  (2) December 2020  (1) September 2020  (1) January 2020  (1) November 2019  (2) October 2019  (2) June 2019  (1) January 2019  (1) December 2018  (1) May 2018  (2) February 2018  (1) January 2018  (1) December 2017  (1) October 2017  (1) June 2017  (1) April 2017  (1) January 2017  (1) December 2016  (1) November 2016  (2) September 2016  (2) May 2016  (1) March 2016  (1) February 2016  (2) January 2016  (1) November 2015  (4) October 2015  (1) September 2015  (3) August 2015  (2) July 2015  (3) June 2015  (1) May 2015  (3) April 2015  (2) March 2015  (1) February 2015  (1) December 2014  (1) November 2014  (2) October 2014  (2) September 2014  (3) July 2014  (3) May 2014  (1) April 2014  (1) March 2014  (1) February 2014  (1) January 2014  (3) December 2013  (3) October 2013  (2) September 2013  (1) August 2013  (2) July 2013  (3) June 2013  (2) May 2013  (3) March 2013  (2) February 2013  (1) January 2013  (3) December 2012  (4) November 2012  (1) October 2012  (1) September 2012  (3) July 2012  (4) June 2012  (2) May 2012  (2) April 2012  (4) March 2012  (2) February 2012  (3) January 2012  (6) December 2011  (2) November 2011  (3) October 2011  (8) September 2011  (4) August 2011  (3)