V-tables solve one problem - method lookup. V-tables are faster than a hash table lookup, yes, but they still mean indirect memory access (so you have to go off and chase pointers around main memory just to make your call), and they're designed for languages where you know the methods that your classes have ahead of time and you know the class of each variable. In Ruby you don't have that. You can call any method on any object.
The only theoretical way I think it would work would be if you knew all the method names ahead of time, gave them all an index, and gave each class a v-table large enough to contain them all. In a Rails application I estimate this might be about 5,000 entries - so 40KB per class. And with singleton classes lots of objects have their own class, so 40KB per object! And as I said that doesn't work anyway as the method names are not known ahead of time - they can be dynamically created and the set of method names is infinite.
But that was method lookup, and that isn't really our problem. I like to use this example from a real Ruby gem to illustrate the bigger problem.
def clamp(min, max, value)
[min, max, value].sort[1]
end
That clamps a value between a min and a max. Using v-tables we could look up the calls to #sort and #[] relatively quickly (well we can't because of the problems with v-tables described above, but I'll keep going) but even with a fast lookup this is still terribly slow code. It creates an array, it sorts it, creating another new array, and then indexes it.
To make that code fast we don't just need fast lookup, we need to take the logic from the sort routine and inline it into this method, and we need to remove the loop in sort and specialise it for just three entries, then inline the methods that calls, such as #<=> to compare the values, then specialise the sort code for the fact that we only wanted the middle entry and remove the code for sorting the other entries, and then we need to remove the allocation of the two arrays.
We need to be able to automatically turn that Ruby code in this.
def clamp(min, max, value)
# deoptimise if things aren't as expected
if value < min
min
elsif value > max
max
else
value
end
end
(Pretend that the calls to #> and #< are simple operators like in C). There's not even any lookup there any longer - so lookup was never really part of the problem.
And crucially, we need to be able to reverse all that inlining if someone monkey patches any of those methods. V-tables don't help us do any of that, but deoptimisation allows us to be in the middle of executing code like that, and reverse the inlining and the specialisation, allocate the objects we removed the allocation of, and keep going after a monkey patch.
The implementation of Ruby I work on, JRuby+Truffle, does that kind of optimisation for real.
I wrote a thesis about all of this http://chrisseaton.com/phd/