On top of that, LLVM is a massive dependency.
I only looked at NativeJIT a few minutes but it seems to solve both of these issues. It's pretty small in terms of API surface // total amount of code and is explicitly designed for a usecase where compilation happens as part of a user-issued query (that needs to be fast).
You can't really compare LuaJIT and LLVM directly, because LuaJIT is a trace compiler. A LuaJIT trace is a linear sequence of instructions with no control flow, which makes optimization much easier. LLVM on the other hand is statically compiling code consisting of many basic blocks and potentially complicated control flow between them.
So LLVM's job is much harder. LuaJIT's optimizer doesn't have to work nearly as hard to get a similar quality of code.
That's arguable. Ravi[1] is a Lua implemented with an LLVM-based JIT. The benchmarks here[2] compare runtime performance of Ravi vs. LuaJIT. The Ravi timings don't include compilation time, the LuaJIT timings do. Sometimes LuaJIT siginficantly outperforms Ravi, sometimes it's on par, sometimes worse. But the results don't suggest that there is less (effective) optimisation going on.
[1] https://github.com/dibyendumajumdar/ravi
[2] http://the-ravi-programming-language.readthedocs.io/en/lates...
Optimization pipelines are invariably language-specific. If you were to somehow make LuaJIT into a C/C++ compiler without doing any work on its optimizer, you would get similarly poor results.
Clang -> Sulong -> Java bytecode -> Luje [1]? May need more turtles :)
Technically, one reason -of several- this probably wouldn't work without significant effort is that Sulong relies on Graal's FFI intrinsics. But those should be convertible to LuaJIT FFI calls (in theory).