Great article! At first I didn’t see the significance of the new attribute, but now I see that forcing the compiler to emit a tail-call even in unoptimized builds (and breaking the build if it can’t) is important.
The referenced article about the design of wasm3 is killer — I came across it a few months ago and wished I’d seen it a year ago when I was implementing a simple byte code interpreter. It spells out the advantages of the threaded call style hot use the old FORTH term) very clearly.
FYI @haberman, I believe there’s a typo (thinko?) in the following sentence; “caller” should be “callee”:
The preserve_most attribute makes the caller responsible for preserving nearly all registers, which moves the cost of the register spills to the fallback functions where we want it.
This is awesome. I maintain a programming language interpreter, and now I want to rewrite it using this technique. Plus, it’s cool that the tail-threaded interpreter technique is applicable to a wider domain, like protobuf parsing. What else could I parse this way?
If I use this technique, then does it block my ability to compile to WASM, or can LLVM generate WASM code that doesn’t explode the stack when I use ‘musttail’? Tail calls are a WASM proposal, in “implementation phase”, but Firefox has been stalled on this for two years, last I checked. I’m just not sure if LLVM ‘musttail’ depends on WASM tail calls.
That is a great question. I don’t know the answer to it. LLVM has had a “musttail” attribute at the IR level for a while, the Clang change just piggybacked on this existing work. I assumed this means that tail calls are supported on all targets. But I’m not sure if there are complications that would prevent this on some targets, like wasm.
i had heard that luaJIT was so complex that basically nobody besides mike pall could maintain it, but i didn’t realize it was written in assembly!
enjoyed learning more about careful optimization in this article and the interesting connections between programming style & relationship with compiled output.
Hi there, article author here. I’m glad you enjoyed the article. LuaJIT’s interpreter is written in assembly, but the rest (parser, optimizer, code generator, etc) are written in C.
Great article! At first I didn’t see the significance of the new attribute, but now I see that forcing the compiler to emit a tail-call even in unoptimized builds (and breaking the build if it can’t) is important.
The referenced article about the design of wasm3 is killer — I came across it a few months ago and wished I’d seen it a year ago when I was implementing a simple byte code interpreter. It spells out the advantages of the threaded call style hot use the old FORTH term) very clearly.
FYI @haberman, I believe there’s a typo (thinko?) in the following sentence; “caller” should be “callee”:
You are correct, thanks for the heads up!
This is awesome. I maintain a programming language interpreter, and now I want to rewrite it using this technique. Plus, it’s cool that the tail-threaded interpreter technique is applicable to a wider domain, like protobuf parsing. What else could I parse this way?
If I use this technique, then does it block my ability to compile to WASM, or can LLVM generate WASM code that doesn’t explode the stack when I use ‘musttail’? Tail calls are a WASM proposal, in “implementation phase”, but Firefox has been stalled on this for two years, last I checked. I’m just not sure if LLVM ‘musttail’ depends on WASM tail calls.
That is a great question. I don’t know the answer to it. LLVM has had a “musttail” attribute at the IR level for a while, the Clang change just piggybacked on this existing work. I assumed this means that tail calls are supported on all targets. But I’m not sure if there are complications that would prevent this on some targets, like wasm.
i had heard that luaJIT was so complex that basically nobody besides mike pall could maintain it, but i didn’t realize it was written in assembly!
enjoyed learning more about careful optimization in this article and the interesting connections between programming style & relationship with compiled output.
Hi there, article author here. I’m glad you enjoyed the article. LuaJIT’s interpreter is written in assembly, but the rest (parser, optimizer, code generator, etc) are written in C.
FWIW, PHP’s JIT is actually basically LuaJIT’s with a lot ripped out of it.