Hacker Newsnew | past | comments | ask | show | jobs | submit | _cogg's commentslogin

Yeah, I expect the real advantage of a JIT is that you can perform proper register allocation and avoid a lot of stack and/or virtual register manipulation.

I wrote a toy copy-patch JIT before and I don't remember being impressed with the performance, even compared to a naive dispatch loop, even on my ~11 year old processor.


The difference between interpreters and simple JITs has narrowed partly due to two factors: better indirect branch predictors with global history, and wider execution bandwidth to absorb the additional dispatch instructions. Intel CPUs starting with Haswell, for instance, show less branch misprediction impact due to better ability to predict jump path patterns through the interpreter. A basic jump table no longer suffers as much compared to tail-calling/dispatch or a simple splicing JIT.


Exactly, and it's not just register allocatio: but for many languages also addign proper typing, some basic data flow optimization, some constant folding, and a few other things that can be done fairly quickly, without the full set of trees and progressive lowering of the operators down to instruactions.

What's odd about the "JIT vs interpreter" debate is that it keeps coming up, given that it is fairly easy to see even in toy examples.


Thank you! Not the author, but I'm also building a compiler. I've stumbled across these tests before and mostly just been irritated and confused about what to do with them.


Yeah, I was totally unaware of this. The namespace appears to be blocked in the sandbox -- probably rightfully so -- but now I'm curious as well. I might have to test it out and write a little addendum.

Edit: Looks like it's slower by a pretty good margin (~3.6 seconds). It's certainly possible I'm doing something stupid. This would be really nice to have for webassembly, where I'm convinced I need to implement some sort of virtual register allocation, and I'm still not entirely sure about control flow.


Author here. My background is in rust if anything. Honestly, I prefer to avoid playing these clever games with type systems unless it's really necessary. It just ended up being the perfect tool for this very specific problem. (How do I compile code in a sandbox that exposes a limited reflection API?)


You used to have to be extremely careful to keep the JIT happy, but I think this has been partially solved in LuaJIT 2.1.

Calling C functions using the old stack API would cause the JIT to abort. In Garrysmod's case, that includes such simple operations as constructing and performing arithmetic on vectors.

So when I was building a high-performance voxel library for Garrysmod, I ended up splitting my hot code into chunks that the JIT compiler would usually be happy with. One fast loop to generate a mesh, then a slow loop to convert that into a mesh structure the engine wants. Very carefully designed methods for bit-packing trees of 12-bit integer voxel data into flat tables of floats.


Any video/blogpost of your voxel library in action? Sounds interesting.


It it still true that generating bindings for luajit is easier than with plain Lua? When I used it for a toy project that was the main reason I chose luajit, especially since the project was written in c++.


Writing bindings isn't something I have a lot of experience with. The main difference I'm aware of is the FFI system, which creates bindings from C headers, and will result in faster calls with good JIT support. I assume it introduces some extra security challenges if you care about that. You'll still probably need to write some wrappers, either C-side or Lua-side if you want a nice API. I know there are other tools for creating bindings, but again, not my area of expertise.


In my experience it very much is. Most of the LuaJIT code I write is just metatable classes around C libraries like SDL. Just being able to write C structs and lua functions is a dream. Having to manually deal with the stack from C-side is a PITA.


I've been thinking a lot about embedded scripting lately, to the extent that I've decided to roll my own language. I agree with all your points, but here are some of my own thoughts:

It should strive to be familiar for users of the host language, not invent weird new syntax. This is ultimately a personal preference, but what I want is a script-oriented rust: Dispense with some ugly stuff that makes it hard to compile or analyze (borrow checker, macros (maybe), giant core+std libs), but keep enough of the things that make it good (inferred static types, expression oriented, pattern matching).

Regarding the "no GC" point: My idea is to just not store any persistent state inside the script engine. Allocate temporary objects in arenas which only live for the duration of a top-level call. If you want persistent state, expose it through bindings. This has the added benefit of making hot reloading trivially easy -- when there's no state, there's nothing for your hot reloading system to break. There are some pretty obvious pitfalls of this. It could totally blow up in my face, so the door is open to adding optional global state and/or garbage collection down the line.

I have a very(!) minimal prototype, and I've written enough of a compiler before that I'm confident I can eventually produce something that works. Whether it lives up to my aspirations is a different story.

If you want something that actually exists now, maybe look into AngelScript. I haven't personally used it, but it's statically typed and supposedly has good C++ integration.


Yup I am actually using AngelScript in my current project since it’s currently the least worst option for me! Having the smoothest experience binding with my C++ engine so far.

I also started a side project making a strongly-typed scripting language compiler / VM a few months ago, but it’s currently on hold since I’m trying to not do too much yak shaving. But maybe someday…


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: