5 ms·
The big gain in speed will come from optimizing away the "meta_send_op_plus" operation. That has to do a hash lookup, which is much slower than an array index.
by richcollins 17y ago
The big gain in speed will come from optimizing away the "meta_send_op_plus" operation. That has to do a hash lookup, which is much slower than an array index.
Ruby should be taking the same route (PIC) that the Javascript VMs are. Perhaps this is planned for one of the Ruby VMs but I haven't heard anything along these lines yet.
- vidarh 17y agoI'm working on an ahead of time compiler for Ruby as a sort of bastard child of my "Writing a compiler in Ruby" article series, and yes, PICs will be one of many essential steps to get decent performance out of Ruby (far down the list though, as I'm still far from having something that works :) ). I believe the Rubinius guys have been looking at PICs or similar methods as well. You can actually do better in many cases, by using C++ style vtables which only requires an array lookup. The are two caveats with vtables for Ruby: Since all objects inherit from Object, all classes need a vtable large enough to hold all methods known at compile time, and secondly you need a fallback mechanism to handle method names not known at compile time. The size overhead is actually not necessarily so bad for typical apps - my compiler itself would have a vtable overhead of about 40K ("vasted" vtable slots) but the hash approach also have (smaller) overheads so the total amount of memory wasted is even lower. You also need to handle re-definition of methods at compile time, but that's a simple matter of propagating the vtable change down the inheritance hierarchy until you reach the bottom or a subclass that has already overloaded the method (Prof. Michael Franz, who's one of the guys behind "trace trees" which is also gaining traction in the JS world wrote a report on using that method to add runtime interface - or protocol - changes to Oberon back in 93 I think). It makes dynamic method redefinition slower, but that's far more rare than dynamic method calls. There are other parts that are trickier. You can redefine Fixnum for example, which means that you need to either do lots of analysis and have a fallback prepared, use type tagging (like MRI) or make integers actual objects. The alternatives are either difficult (analysis+fallback), bloats and slows your code (type tags and objects) and/or causes extra memory usage and pressure on your FC (making integers real objects). You also have the "require" problem. A common Ruby idiom is to loop over a directory and require all files in it. Do you require it at compile time, or at runtime? Granted, that part is easier for a JIT (though even an ahead of time compiler for Ruby will need to include either a small VM or a JIT to handle eval and completely dynamic require/load's) Not to mention the fun little issue of code executing in a class definition, meaning you don't actually even know what methods a class has without potentially executing code. Heck, for a really pathological case, more than one Ruby ORM establishes a database connection and executes queries in the class definition in order to add methods to the class then and there. All of this makes Ruby really painful to compile efficiently since you know so little about the program without actually executing it.
- steveklabnik 17y agoI just wanted to say thanks for writing all of those "Write a compiler in Ruby" articles. They've been really interesting and informative. For a little while, I was following along, but targeting x86_64 rather than x86 so that it didn't feel like I was just copy/pasting everything that you did...
- vidarh 17y agoThat's great... More parts will be coming - other parts of life has just been interfering :) If you ever feel like trying your hands at making any changes, it's on all on Github. At the moment I'm just focusing on getting attr_reader and friends working. Sounds simple, but since I wanted to write attr_reader and attr_writer mainly in Ruby it's a rabbit hole that required me to get basic parts of Symbol and String working, as well as define_method, fixing various method dispatch issues, fixing string interpolation and more; those changes will make up the bulk of the content of the next couple of parts I write. Once all those pieces are in place a lot of the rest of what's needed to compile a fairly decent subset of Ruby is pretty simple (though lots of gruntwork). With some luck (and enough spare time) I hope to get the compiler self-hosted by the end of the year.
- BigZaphod 17y agoStupid question, but in this context what does "PIC" stand for? The best I came up with was "Partially Inlined Code."
- ionfish 17y agoPolymorphic inline caching. This article might give a bit more insight into how modern JavaScript virtual machines like V8 and SFX use it. http://techon.nikkeibp.co.jp/article/HONSHI/20090106/163620/ http://techon.nikkeibp.co.jp/article/HONSHI/20090106/163620/