5 ms·
Compiling Ruby to machine language
- deleted 1y ago[deleted]
- pasxizeis 1y agoReally happy to see Pat keeping it up! His first Ruby under a Microscope book but also his blog posts are amazing and a major source of inspiration for me. I did meet him personally in a Euruko conference. Such a great person.
- pat_shaughnessy 1y agoWhat a lovely comment - thank you!
- topato 1y agowhoa, the man himself! I second the praise, an all around excellent writer!
- chao- 1y agoI loved Ruby Under a Microscope when I first read it, and using that knowledge was able to have fun with some CTFs years ago. I haven't kept up with the evolving Ruby implementation internals, so I will sure as heck buy this new version of the book.
- UncleOxidant 1y agoI used Ruby a lot from about 2002 to 2010. Haven't used it much since then, but this article really makes me want to get a copy of the upcoming version Ruby Under a Microscope.
- pmarreck 1y agoHow fast is Ruby, lately? I haven't used it in about 10 years
- baggy_trough 1y agoFast enough for most normal sites.
- vidarh 1y agoI have a prototype ahead-of-time Ruby compiler. It's woefully incomplete - I've just recently picked it up again after years of inactivity, with heavy AI use to pursue rubyspec compliance (it's nowhere close). The point of mentioning that: MRI - the main Ruby interpreter - is fast enough that competing against it with an unoptimized compiler goes really badly unless you do a lot to optimise the garbage collector (I haven't yet). So it's "fast". There's plenty more that can be done to make it much faster still, but even before yjit, MRI had gotten pretty decent.
- pansa2 1y ago> How fast is Ruby, lately? I did recent testing that showed it to be faster than Python but slower than Lua: Lua, Ruby and Python ran my benchmark in 12, 18 and 25 seconds respectively. This was measured using the latest versions of each language (5.4, 3.4 and 3.13), using only the interpreters, no JITs. > I haven't used it in about 10 years It looks like the relative performance of the three languages hasn't changed much since I did a similar benchmark with Ruby 2.0, about that long ago.
- jlarocco 1y agoIIRC MacRuby used to compile to native code on OSX using LLVM, and was supposed to support native OSX APIs and Objective-C frameworks. It always seemed like a neat idea, and a slick integration, but I guess Apple moved to Swift instead. I'll have to pick up a copy of this "Ruby Under a Microscope" book when the new version comes out. I've always liked Ruby, I just haven't had much chance to use it.
- eek2121 1y agoTypical. I may get absolutely destroyed for this, but being professionally proficient in a ton of languages, including Ruby and the ones I mention below, and the ones I'm about to mention: This sounds like Microsoft when they moved from VB6 to VB.Net. At least they have a good thing going with C# though. VB6 was quite an interesting beast. You could do basically everything that you could do in languages like C/C++, but in most cases, you could churn out code quicker. This even extended to DirectX/Direct3D! For Web pages? ASP Classic. The tl;dr is that I really wish that ease of development were prioritized along with everything else. One of the reasons I like Ruby is the elegance of the language and ease of using it. Note that I've been using it since the mid 2000s or so, but not exclusively (both it and VB6 defined my career, however). C# is my second most favorite. If Ruby had the GUI design tools VB6 had, it would be interesting to look at the popularity stats Anyway, I'm rambling, so there is that. ;)
- blacksmith_tb 1y agoWhat about something like Shoes[1]? I have played with it a little, just to make a simple UI to run some scripts I can run fine in a shell myself, but less-technical people may be too scared to fire up Terminal.app in order to do the same... 1: http://shoesrb.com/ http://shoesrb.com/
- pizza234 1y agoShoes was very limited, and could only be used for extremely simple applications.
- 1y ago
- le-mark 1y agoI find that using C as an intermediate step really helps conceptualize this process. It can be tough to imagine how to represent a language like ruby as C. Essentially you have to start from the point that everything is an object and method calls on objects, then build up from that. Then C to assembler is more manageable. Ymmv.
- shevy-java 1y agoI always found the steps to assembler harder. I'd wish we could have both a hardware interface that is resembled at the same level as the software - but super simple. With that I mean super-simple to understand and write; assembler is simple but not easy to understand. The complexity scales quickly. That's why C was successful - it was much easier to reason about the system in C than it was in assembler/assembly.
- pansa2 1y ago> To find hot spots, YJIT counts how many times your program calls each function or block At first glance this seems too simple. Compare it to JavaScript JITs, which IIRC can compile hot spots even in functions that are only called a few times (e.g. those that contain heavy loops) via on-stack replacement. (Although I’ve also heard on-stack replacement called a “party trick” - more useful for optimising benchmark scores than for real code.) But on the other hand, Ruby’s language design might help here. Idiomatic Ruby uses blocks for loop bodies - so can Ruby JITs optimise long-running loops by treating the loop body as just another function?
- pat_shaughnessy 1y ago> Idiomatic Ruby uses blocks for loop bodies Yes that's something I want to dig into and explore in this chapter... when exactly does Ruby's JIT compiler activate and optimize our code? And you're right: since Ruby will JIT blocks as if they were separate function many loops will be optimized using this simple heuristic.
- hoten 1y agoOnce a YJIT block executes enough times to warrant compilation, how does this system keep track of which types to compile for? Each block is tracking how many times it's entered, but not how many times it's entered for int or float or whatever types; so in the given example how would Ruby handle the compilation of the "opt_plus" stub when the input types may vary? And by what process is the correct compiled block used depending on the input variable types?
- pat_shaughnessy 1y agoThat's the magic of YJIT, and what I'll describe in the rest of Chapter 4. YJIT uses a "wait-and-see" approach, and often defers compilation of the block/function until the actual types are provided by your program. And YJIT then keeps track of separate block versions based on the operand types, and can call the appropriate block version as needed. This basic algorithm is called "Basic Block Versioning." Maxime Chevalier-Boisvert from Shopify has some great presentations online about this; for example [1]. I believe ZJIT, the newer JIT engine, uses a different approach. I'm exploring that now. [1] https://www.youtube.com/watch?v=zO9_uTaELCw https://www.youtube.com/watch?v=zO9_uTaELCw — RubyConf 2021 - YJIT - Building a new JIT Compiler inside CRuby by Maxime Chevalier Boisvert.
- deleted 1y ago[deleted]
- killme2008 1y agoGlad to see that Ruby Under a Microscope is still being updated. It’s an essential read for anyone who wants to understand how Ruby works internally — and I truly enjoy reading it.
- jweir 1y agoSpeaking of compiling Ruby. And Stripe coders who have used the Sorbet compiler? https://sorbet.org/blog/2021/07/30/open-sourcing-sorbet-compiler https://sorbet.org/blog/2021/07/30/open-sourcing-sorbet-comp...
- deleted 1y ago[deleted]
- vidarh 1y agoIt seems to be gone from the repo, and doesn't seem to be worked on any more? A shame. AOT compiling Ruby is hard. I'm trying [1] [2]. Sorbet would be in a good position because part of the challenge of making it fast is that Ruby has a lot of semantics that are rarely used but that makes making compiled Ruby fast really hard. E.g. the bignum promotion adds overhead to every single operation unless you can prove invariants about the range of the values; the meta-programming likewise adds overhead and makes even very basic operations really expensive unless you can prove classes (or individual objects) aren't being mucked with... So starting with type checking is an interesting approach to potentially allow for compiling guarded type-specific fast paths. If my compiler ever gets close enough to feature complete (it's a hobby project, so depends entirely on how much time I get, though now I also justify more time for it by using it as a test-bed for LLM tooling), it's certainly a direction I'd love to eventually explore. [1] https://hokstad.com/compiler https://hokstad.com/compiler (not updated for a decade) [2] https://github.com/vidarh/writing-a-compiler-in-ruby/ https://github.com/vidarh/writing-a-compiler-in-ruby/ (updated now primarily by Claude Code; it's currently focusing on actually passing RubySpec and making speedy progress, at the cost of allowing some fairly ugly code - I do cleanup passes occasionally, but most of the cleanup will be deferred until more passes)
- cutler 1y agoMaking dynamically typed, single threaded languages faster via JIT usually comes at the cost of a significant increase in memory consumption which for businesses smaller than Shopify is a much more significant factor.
- byroot 1y agoIs it? Smaller business usually comes with smaller applications. Most cloud and hardware vendors give you about 4GiB of RAM per core, maybe only 2 when using "CPU optimized instances", that's huge and leave plenty of space for a couple hundred MB of JITed code.
- MaxBarraclough 1y agoAgreed. In Java land, if I understand correctly the OpenJ9 JVM can (or at least could) beat HotSpot in memory consumption, while being slightly behind in execution times. It still sees only limited adoption. This may be just because it's seen as an 'alternative' option, less trustworthy than HotSpot, but it also seems to indicate the HotSpot developers aren't prioritising memory consumption. https://bell-sw.com/announcements/2022/06/28/hotspot-vs-openj9-performance-comparison/ https://bell-sw.com/announcements/2022/06/28/hotspot-vs-open... https://eclipse.dev/openj9/performance/ https://eclipse.dev/openj9/performance/ (non-impartial source, of course)
- AdieuToLogic 1y agoWhile not related to compiling Ruby, I found the book "Enterprise Integration with Ruby"[0] to be enlightening regarding using it outside of web applications. 0 - https://www.goodreads.com/book/show/624316.Enterprise_Integration_with_Ruby https://www.goodreads.com/book/show/624316.Enterprise_Integr...
- Adam2025 1y agoGreat clear explanation of how YJIT and ZJIT work. The details on block compilation and counting make JIT internals more accessible to Ruby developers.
- Alifatisk 1y agoEver since I discovered MRuby, I’ve had fun converting my projects and scripts into standalone executable files.