June 20th, 2024

My experience crafting an interpreter with Rust (2021)

Manuel Cerón details creating an interpreter with Rust, transitioning from Clojure. Leveraging Rust's safety features, he faced challenges with closures and classes, optimizing code for performance while balancing safety.

Read original articleLink Icon
My experience crafting an interpreter with Rust (2021)

Manuel Cerón shares his journey of creating an interpreter with Rust, inspired by the book "Crafting Interpreters" by Bob Nystrom. He initially implemented a tree-walking interpreter in Clojure and then transitioned to Rust for a bytecode VM. Embracing Rust's safety features, he leveraged the standard library and advanced type system, finding joy in writing the compiler but facing challenges with advanced concepts like closures and classes due to Rust's strict rules. Developing a garbage collector in safe Rust posed difficulties, leading to a simple design using trait objects and tombstones. Despite initial hopes of matching the speed of a C implementation, performance testing revealed significant slowdowns, prompting Manuel to optimize his code by introducing unsafe blocks. Profiling identified issues with the garbage collector implementation and pointer dereferencing, highlighting areas for improvement to enhance performance. Manuel's experience showcases the balance between Rust's safety features and performance optimization in interpreter development.

Related

Trealla Prolog: Compact and efficient Prolog interpreter

Trealla Prolog: Compact and efficient Prolog interpreter

Trealla Prolog is a compact interpreter written in C, compliant with ISO Prolog. It supports unbounded integers, UTF-8 atoms, efficient strings, and runs on Linux, Android, and WebAssembly. It offers C integration, SQLite access, concurrency features, and experimental functionalities. The project is open source under the MIT license.

SquirrelFS: Using the Rust compiler to check file-system crash consistency

SquirrelFS: Using the Rust compiler to check file-system crash consistency

The paper introduces SquirrelFS, a crash-safe file system using Rust's typestate pattern for compile-time operation order enforcement. Synchronous Soft Updates ensure crash safety by maintaining metadata update order. SquirrelFS offers correctness guarantees without separate proofs, quickly verifying crash consistency during compilation. Comparative evaluations show SquirrelFS performs similarly or better than NOVA and WineFS.

Memory Model: The Hard Bits

Memory Model: The Hard Bits

This chapter explores OCaml's memory model, emphasizing relaxed memory aspects, compiler optimizations, weakly consistent memory, and DRF-SC guarantee. It clarifies data races, memory classifications, and simplifies reasoning for programmers. Examples highlight data race scenarios and atomicity.

Writing an IR from Scratch and survive to write a post

Writing an IR from Scratch and survive to write a post

Eduardo Blázquez developed an Intermediate Representation (IR) for the Kunai Static Analyzer during his PhD, aiming to enhance Dalvik bytecode analysis. The project, shared on GitHub and published in SoftwareX, transitioned to Shuriken. Blázquez drew inspiration from Triton and LLVM, exploring various IR structures like ASTs and CFGs. MjolnIR, Kunai's IR, utilized a Medium Level IL design with control-flow graphs representing methods. Blázquez's approach involved studying compiler design resources.

Homegrown Rendering with Rust

Homegrown Rendering with Rust

Embark Studios develops a creative platform for user-generated content, emphasizing gameplay over graphics. They leverage Rust for 3D rendering, introducing the experimental "kajiya" renderer for learning purposes. The team aims to simplify rendering for user-generated content, utilizing Vulkan API and Rust's versatility for GPU programming. They seek to enhance Rust's ecosystem for GPU programming.

Link Icon 4 comments
By @jll29 - 4 months
Thanks for sharing this experience - implementing a VM with GC is a core example of where a systems programming should shine.

The result shows that a direct solution (in less time than the C solution might have taken?) was not achieved, which can be attributed to inexperience. Then he got the safe version running, but with a big performance penalty. In a third stage, the code got more and more "unsafe" and performance rose close to the C implementation - without ever reaching it.

Some results from this - very well described - experiment is:

- Rust is a good language, but in development: the Rust developers still have a lot of work to do.

- IMHO, the safe version here is at the sweet spot; stop optimizing there with all the unsafe tricks (playing with the hash map is still fair game) and leave the rest to the compiler writers. Once they have put the amount of effort in that has gone into compiling Java, the graphs will look different. Safety is priceless, and who knows what buffer weaknesses clox has that can be exploited.

The post's writing is very clear, and I'm particularly grateful for the explanation of the problem the borrow checker has with GC in the main loop, and I can see how a lot of re-factoring solves one type issue in one corner only for it to crop up in another - thanks!

By @wudangmonk - 4 months
I know nothing about rust but if you are struggling against the borrow checker because you want to implement something like linked lists or anything it doesn't want you the obvious solution is to allocate all your memory upfront and create your own allocator where you pass around indexes and thus bypass the borrow checker completely. I think this is what the author does? not really clear as he seemed to be constantly struggling with the language even after that.

I gotta say its not selling me on rust if bypassing the borrow checker with my own allocations still results in having to jump through so many hoops and struggle against the language.

By @saghm - 4 months
Looks like this should be marked with (2021), assuming date at the top of the blog post is correct