Hacker News new | ask | show | jobs
by imtringued 244 days ago
I'm not really interested in building an interpreter, but the part about scalar out of order execution got me thinking. The opcode sequencing logic of an interpreter is inherently serial and an obvious bottleneck (step++; goto step->label; requires an add, then a fetch and then a jump, pretty ugly).

Why not do the same thing the CPU does and fetch N jump addresses at once?

Now the overhead is gone and you just need to figure out how to let the CPU fetch the chain of instructions that implement the opcodes.

You simply copy the interpreter N times, store N opcode jump addresses in N registers and each interpreter copy is hardcoded to access its own register during the computed goto.

3 comments

You run into the same problem a CPU does: if you have dependencies between the instructions, you can't execute ahead of time. Your processor has a bunch of hardware to efficiently resolve conflicts but your interpreter does not.
Depending on the bytecode, instructions might be variable-length, which means that you need to execute a nontrivial amount of logic to fetch more than just the next bytecode or handler. That said, I tinkered with adding a prefetch to Wizard's interpreter which basically moves the load of the next handler from the dispatch at the end to the first thing in the handler, and saw something like a 5% improvement.
The thing you're suggesting makes sense, but it's far more efficient to do in hardware. You might say that you could do it on one of the many cores available on your modern processor, but it turns out that synchronizing them to your main thread is really inefficient -- and anyway, they're busy running your HN browser threads and your YouTube music video.