http://article.gmane.org/gmane.comp.lang.lua.general/75426
Worth noting that IIRC, for a while LuaJIT in interpreted mode was able to beat V8 in optimized mode not all that infrequently (although it depended on the use case, they are different languages, and I do not know if this is still the case).
V8 had no optimizing compiler when Mike Pall sent his (in)famous mail about "LuaJIT interpreter beating V8 compiler"[1].
Also usual disclaimers about cross-language benchmarks apply (e.g. nobody looked how those benchmarks differ between JS and Lua implementation).
Very suboptimal might be a slight overstatement. I can see a way, given known register calling conventions, that you could write an interpreter written as tail calls and post-process the machine code to effectively JMP instead of CALL. Guaranteed tail calls would save you a bunch of effort, and register calling convention would give you some guarantees about consistent allocation.
https://en.wikipedia.org/wiki/Threaded_code
When written in C, is typically done using GCC's computed goto and the && label address-of operator extension.
Writing the handlers in machine-agnostic assembly is interesting; I'm guessing they want to tune the output more than writing the handlers in C would let them, or they can't rely on something like GCC's computed gotos.