Simple Virtual Machines

Terrence Parr presented an introduction to virtual machines. He implemented a simple virtual machine and put the code in both Java and C varieties on GitHub:

I decided to implement the same virtual machine in one of the worst languages for such a task: Lua. Lua itself uses a virtual machine. Now we have a virtual machine inside another virtual machine. Furtheremore, Lua doesn’t have an integer type or the switch statement. This means the default word size is actually a double and the dispatch loop is fairly verbose in comparison to the C-inspired languages. I tried a number of dispatch methods, including a dispatch table of functions and a giant series of if ... else statements. While the dispatch table is more idiomatic Lua, it’s a bit slower.

Computed Goto

Then I forked the C implemention, added the CALL/RET opcodes and converted the giant switch statement into a computed goto. I expect the computed goto to offer a significant improvement in performance. Behold the hackish glory:

Performance

Compare the time to calculate factorial(12) one million times. Run on a Intel i5-3570K, average of five runs.

Simple virtual machine implementations:

luajit:         10.940s [13.7x]
java:            3.114s [3.90x]
c switch:        2.045s [2.56x]
c goto:          0.798s [1.00x]

Other virtual machines:

luajit           0.047s [0.06x]
java             0.331s [0.41x] 
lua              1.591s [1.99x]
ruby             2.569s [3.22x]
python           4.175s [5.23x]

Performance is as expected. LuaJIT, which seems to compile every opcode, was not as fast as Java. But for a dynamic language, 3.5x slower isn’t bad. While Java has a world famous JIT compiler, this non-representative case shows it to be half the speed of the equivalent C. The computed goto is ugly and non-portable but, as expected, it is very fast. The code used to time the other languages is on gist.