I think I may be able to get very close to native performance. I don't want to sound like an asshole by appealing to authority, but you aren't talking to a teenager writing an interpreter from their parent's basement. I have 21 years of programming experience, a PhD in compiler design and multiple published papers. I have some idea what I'm talking about.
> Why do you think creating a similarly good JIT compiler to a very similar design would be any easier in case of UVM?
The design is superficially similar to the JVM but it's also quite different. UVM's bytecode is untyped. It maps fairly directly to the x86-64 and ARMv8 instruction sets. If you want an idea of how a simple JIT compiler for a bytecode like that can perform, you should look at the performance of Apple's Rosetta. But, I actually think I can build something that yields better performance than that :)
Also, what does “native performance” even mean here? Only removing the interpreter overhead?
At the moment I'm in no rush to actually write the JIT compiler because I think it's faster to iterate with an interpreter. I want to flesh out the VM and its APIs, test the hell out of everything and develop the system a bit more first.
The interpreter runs at something ~400 million instructions per second on my laptop, which is probably close to the performance of an old school Pentium 2 chip, so it's actually fast enough to run a lot of non-trivial software. With even a really basic JIT I should be able to hit 10x that throughput. I've benchmarked code out of GCC and it runs about 27 times faster (on a microbenchmark).
If you are interpreting instructions a simple one will be more than enough. Classes are its primitives, you just create a basic runtime representation for them with name, superclass, implemented interfaces and the methods’ bytecodes. Then an object can be as simple as a header containing a pointer to the class’s representation and then a listing of its fields, which can all be 64bits. And an array can have the exact same representation as well, with the first element being its size.
All APIs are just classes with some methods that may be “native”, which are linked to a native implementation (basically just a function pointer). This is how file access and the like becomes possible.
> Otherwise what you have is not what people expect to find in a JVM
You can just say that it is a partial implementation that doesn’t support the whole of the Java standard lib. It’s not unheard of (e.g. Java ME is a subset that runs on every SIM and bank card).
> I'm also under the impression that building a good JIT for a JVM would be a massive undertaking
Well, then just go with an okayish JIT. With all due respect, you ain’t going to beat the JVM with your UVM’s JIT compiler, not even close. Why do you think creating a similarly good JIT compiler to a very similar design would be any easier in case of UVM?
But don’t get me wrong, I just ask these questions because I dislike NIH syndrome and I believe there are useful lessons to be learned from the past. But you should be able to answer why the thing you do is any different (unless it is for learning). And the JVM spec is a surprisingly good read, and you can sure take great ideas from that.